pinctrl子系统的使用

一、pinctrl子系统设备树配置

  有了pinctrl子系统以后,驱动就可以操作pinctrl子系统的接口函数完成I/O操作了,而不需要自己去配置了。一般pinctrl子系统驱动是由芯片原厂的BSP工程师实现好的。驱动工程师通过配置设备树去使用pinctrl子系统。有些I/O口具有不同的状态(state),比如在正常工作的时候这一组I/O口被配置成uart接口,休眠时配置成GPIO接口且输出为高电平。pinctrl子系统的设备树配置也是遵守service和client结构。

举个例子:这里的device节点成为pinctrl子系统中的一个client设备,因为其使用了pinctrl子系统里面提供出来的接口。pinctrl就是pincontroller的缩写。

//client节点
device {
    pinctrl-names = "default", "sleep"; //使用pinctrl-names来表示设备的状态(state),这里有2个,分别为默认状态和休眠状态。
    pinctrl-0 = <&state_0_node_a>; //第0个状态对应于"default"状态,对应的引脚在pinctrl-0里面定义。
    pinctrl-0 = <&state_1_node_a>; //第1个状态对应于"sleep"状态,对应的引脚在pinctrl-1里面定义。
};

//service节点
pincontroller {
    state_0_node_a {
        function = "uart0";
        groups = "u0rxtx", "u0rtscts";
    };
    state_1_node_a {
        function = "gpio";
        groups = "u0rxtx", "u0rtscts";
    };
};

  上面的是对一组引脚的复用,在不同状态下复用为uart引脚或gpio引脚,称为“Generic pin multiplexing node”(复用节点)。还有一种配置叫做“Generic pin configuration node”(配置节点)是对引脚功能的配置,不同的状态(default、idle、sleep...)配置成不同的功能。

一个配置节点的例子如下:

//client节点
device {
    pinctrl-names = "default", "sleep"; //使用pinctrl-names来表示设备的状态(state),这里有2个,分别为默认状态和休眠状态。
    pinctrl-0 = <&state_0_node_a>; //第0个状态对应于"default"状态,对应的引脚在pinctrl-0里面定义。
    pinctrl-0 = <&state_1_node_a>; //第1个状态对应于"sleep"状态,对应的引脚在pinctrl-1里面定义。
};

//service节点,controller来提供服务
pincontroller {
    state_0_node_a { //复用节点
        function = "uart0";
        groups = "u0rxtx", "u0rtscts";
    };
    state_1_node_a { //配置节点
        groups = "u0rxtx", "u0rtscts";
        output-high; //输出高电平
    };
};

  不论是复用节点还是配置节点,都是来操作这些引脚。对于一个client它可以指定多个状态(state),在每一个状态下都可以指定对应的子节点来描述它的状态。子节点在controller服务侧实现,子节点可以是一个复用节点(把对应的引脚复用成某个功能)也可以是一个配置节点(把对应的引脚配置成某个状态)。

  对于client节点,其设备树书写格式基本上是一致的,统一的。但是对于服务侧的controller节点的写法就五法八门了,有些根本就没有function和group,可以说的上是毫无格式。

举几个实际使用的例子:

1.imx6ull的

//client端:
@uart1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_uart1>;
    status = "okay";
};

//pincontroller服务端
pinctrl_uart1: uartlgrp {
    fsl.pins = <MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX, //名字为UART1_TX的引脚被复用为UART1_DCE_TX功能。
        MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX>; //这里写的是两个宏,所以没有加"&"
};

2.rk3288平台的

//client端
@uart0 {
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; //它使用三个节点来表示三组引脚。
    status = "okay";
};

//pincontroller服务端
gpio4_uart0 {
    uart0_xfer: uart0-xfer {
        rockchip,pins = <UART0BT_SIN>, <UART0BT_SOUT>; //使用rockchip,pins来指定使用哪些引脚,就等效于groups
        rockchip,pull = <VALUE_PULL_DISABLE>; //这两个字段来配置这些引脚的参数
        rockchip,drive = <VALUE_DRV_DEFAULT>;
    };
    uart0_cts: uart0-cts {
        rockchip,pins = <UART0BT_CTSN>; //这里写的是两个宏,所以没有加"&",这里其实是指定了两个引脚。
        rockchip,pull = <VALUE_PULL_DISABLE>;
        rockchip,drive = <VALUE_DRV_DEFAULT>;
    };
    uart0_rts: uart0-rts {
        rockchip,pins = <UART0BT_RTSN>;
        rockchip,pull = <VALUE_PULL_DISABLE>;
        rockchip,drive = <VALUE_DRV_DEFAULT>;
    };
    uart0_rts_gpio: uart0-rts-gpio {
        rockchip,pins = <FUNC_TO_GPIO(UART0BT_RTSN)>;
        rockchip,drive = <VALUE_DRV_DEFAULT>;
    };
};

虽然pincontroller服务端没有统一的格式,但是其里面的概念还是一样的,使用到哪些引脚,这些引脚会被归为一组一组,这些引脚会被复用为某一个功能。

扫描二维码关注公众号,回复: 9849809 查看本文章

二、驱动中怎样使用pinctrl子系统

  对于驱动代码中怎样使用pinctrl子系统,这对驱动工程师来说是透明的,我们驱动中基本不用管,当设备切换状态时(对应设备树中pinctrl-names的状态),对应的pinctrl就会被调用。

1. 在驱动probe之前就先获取了pinctl的各种state

really_probe //drivers/base/dd.c
    /* If using pinctrl, bind pins now before probing */
    //先获取pinctrl引脚配置
    ret = pinctrl_bind_pins(dev); //drivers/base/pinctrl.c
        //1.保存"default"状态引脚配置
        dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT);
        //2.保存"init"状态引脚配置
        dev->pins->init_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT);
        if (IS_ERR(dev->pins->init_state)) { //若init state存在就选择“init” state,否则选择"default" state
            ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
        } else {
            ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
        }
        //3.保存"sleep"状态引脚配置
        dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);
        //4.保存"idle"状态引脚配置
        dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);
    //然后再probe我们的驱动
    drv->probe(dev);

2.若是非要自己调用,也有函数

struct pinctrl * __must_check devm_pinctrl_get_select_default(struct device *dev) //获取"default"状态的pinctrl配置
struct pinctrl * __must_check devm_pinctrl_get_select(struct device *dev, const char *name); //获取name指定的pinctrl配置
void devm_pinctrl_put(struct pinctrl *p); //释放pinctrl配置资源,通常不需要我们调用。

猜你喜欢

转载自www.cnblogs.com/hellokitty2/p/12501493.html
今日推荐