|
| 1 | +-------------------------------------------------------------- |
| 2 | +pinctrl子系统总结 |
| 3 | +-------------------------------------------------------------- |
| 4 | +软件框架: |
| 5 | +1. pinctrl-core |
| 6 | +2. pinctrl-driver (最底层,寄存器操作,根据Function,Group...) |
| 7 | +3. pinctrl-client (具体的设备驱动,SPI,UART,WIFI,GPS设备...) |
| 8 | + |
| 9 | +0.概述 |
| 10 | +目前市面上的ARM SoC提供了十分丰富的硬件接口,而硬件接口在物理上的表现就是一个个的pin(或者叫做pad, finger等)。 |
| 11 | +为了实现丰富的硬件功能,SoC的pin需要实现复用(IOMUX)功能,即单独的pin需要提供不同功能,例如,一个pin既可以作为GPIO,可以也用于i2c的SCL, |
| 12 | +通过pin相关的复用寄存器,来切换不同的功能。 |
| 13 | +除此之外,软件还可以通过寄存器配置pin相关的电气特性,例如,上拉/下拉、驱动能力、开漏等。 |
| 14 | + |
| 15 | + |
| 16 | +kernel3.x之前的内核,对于pin的功能配置都是通过Board File的配置文件(arch/arm/mach-xxx)来初始化的,这种配置方式比较繁琐, |
| 17 | +十分容易出现问题(例如pin的功能配置冲突)。 |
| 18 | +所以kernel 3.x之后,实现了用DTS的板级配置信息来管理的机制,大大改善了对于pin的配置方式,随之一起实现的就是pinctrl子系统。 |
| 19 | + |
| 20 | + |
| 21 | +pinctrl子系统,主要负责以下功能: |
| 22 | +1.枚举、命名通过板级DTS配置的所有pin |
| 23 | +2.对pin实现IOMUX功能 |
| 24 | +3.配置pin的电器特性,例如,上拉/下拉、驱动能力、开漏等 |
| 25 | + |
| 26 | +由此可见,pinctrl子系统地位相当于kernel的pin管理中心,kernel中所有需要pin资源的驱动、子系统都需要通过pinctrl子系统来申请、配置、释放。 |
| 27 | +pinctrl子系统十分重要的。 |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +1. 软件框架 |
| 32 | +不同的SoC,其对于pin的配置方式肯定也不同。对此,pinctrl子系统,(其实linux kernel内部很多驱动子系统,都是这种搞法) |
| 33 | + |
| 34 | +1.将pin的管理方式进行了抽象,形成了pinctrl-core抽象层; |
| 35 | +2.将具体SoC的pin controler隔离出去,形成了pinctrl-driver抽象层; |
| 36 | +3.pinctrl-core和pinctrl-driver层通过抽象接口进行通信; |
| 37 | +4.对于各个需要用到pin的具体设备的驱动,pinctrl子系统将其抽象为pinctrl-client(包括以前的GPIO子系统); |
| 38 | + |
| 39 | + |
| 40 | +通过上面的软件抽象,pinctrl子系统可以很好的应对不同的SoC pin controler的管理需求,可以很好的为不同需要的驱动程序,提供pin的操作服务。 |
| 41 | + |
| 42 | + |
| 43 | +问:GPIO子系统与pinctrl子系统的关系? |
| 44 | +答: |
| 45 | + 按理说,kernel中GPIO子系统和 pinctrl子系统的关系应该非常清楚: |
| 46 | + pinctrl子系统管理SOC的所有管脚,GPIO子系统是这些管脚的用途之一, |
| 47 | + 因此GPIO子系统应该是pinctrl子系统的client(也可叫做backend、consumer),它基于pinctrl subsystem提供的功能,处理GPIO有关的逻辑。 |
| 48 | + |
| 49 | +不过,实际情况却不是这么简单,它们之间有着较为紧密的耦合(看一看kernel中pinctrl和gpio相关的实现就知道了) |
| 50 | +理论上,GPIO子系统作为pinctrl子系统的使用者,其地位应该和普通的设备驱动没有差别,但是由于以下原因导致GPIO子系统与pinctrl子系统的功能出现了耦合: |
| 51 | + |
| 52 | + 1.早在kernel 3.0之前,GPIO子系统就已经出现了,其功能就是管理pin的GPIO功能; |
| 53 | + 2.pinctrl子系统以及DTS机制出现之后,由于GPIO管理的特殊性,并没有将GPIO子系统合并到pinctrl子系统中, |
| 54 | + 而是在pinctrl子系统为GPIO子系统保留了特殊的访问通道,以达到GPIO子系统访问pin的需求; |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +1.1. pinctrl-core |
| 59 | +pinctrl-core抽象层主要的功能就是:三种 |
| 60 | + 1.为SoC pin Controller drvier提供底层通信接口的能力(向下的interface) |
| 61 | + 2.为Driver提供访问pin的能力,即driver配置pin复用能、配置引脚的电气特性(向上的interface) |
| 62 | + 3.为GPIO子系统提供访问GPIO的能力(也算向上的interface) |
| 63 | + |
| 64 | +对于第一种功能来说,其实pinctrl-core抽象层,完全不会去关心底层的pin存在方式以及如何对其配置。 |
| 65 | +那么,pinctrl-core如何完成对底层的pinctrl-driver的控制呢? 其实很简单, |
| 66 | +pinctrl-core与底层pinctrl-driver是通过pin controller descriptor进行通信的。 |
| 67 | + |
| 68 | +该结构定义如下: |
| 69 | +/** |
| 70 | + * struct pinctrl_desc - pin controller descriptor, register this to pin |
| 71 | + * control subsystem |
| 72 | + * @name: name for the pin controller |
| 73 | + * @pins: an array of pin descriptors describing all the pins handled by |
| 74 | + * this pin controller |
| 75 | + * @npins: number of descriptors in the array, usually just ARRAY_SIZE() |
| 76 | + * of the pins field above |
| 77 | + * @pctlops: pin control operation vtable, to support global concepts like |
| 78 | + * grouping of pins, this is optional. |
| 79 | + * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver |
| 80 | + * @confops: pin config operations vtable, if you support pin configuration in |
| 81 | + * your driver |
| 82 | + * @owner: module providing the pin controller, used for refcounting |
| 83 | + */ |
| 84 | +struct pinctrl_desc { |
| 85 | + |
| 86 | + /*pinctrl-driver属性*/ |
| 87 | + const char *name; |
| 88 | + const struct pinctrl_pin_desc *pins; |
| 89 | + unsigned int npins; |
| 90 | + |
| 91 | + /*pinctrl-drive抽象接口*/ |
| 92 | + const struct pinctrl_ops *pctlops; |
| 93 | + const struct pinmux_ops *pmxops; |
| 94 | + const struct pinconf_ops *confops; |
| 95 | + struct module *owner; |
| 96 | +}; |
| 97 | + |
| 98 | +这个pinctrl_desc就是对底层pinctrl-driver的抽象,其中包括了pinctrl-driver的所有属性,以及其具有的所有能力; |
| 99 | + |
| 100 | +这就是典型的面向对象编程的思想,pinctrl-core将底层的pinctrl-driver抽象为pinctrl_desc对象,具体的某SoC pinctrl-driver便是该对象一个实例。 |
| 101 | +pinctrl-core通过该实例,完成对于系统中所有pin的操作。 |
| 102 | + |
| 103 | +但是,具体到pinctrl-driver如何完成pin的相关操作,pinctrl-core其实是不关心的。 |
| 104 | + |
| 105 | +这就将pinctrl-driver的管理的复杂性进行了隔离,与之通信的唯一方式就是预先定义好的抽象接口。 |
| 106 | +这样,不管pinctrl-driver如何变化,只要是按照协议,实例化了pinctrl_desc,那么pinctrl-core就始终可以管理系统所有的pin。 |
| 107 | + |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | +1.2.最底层的pinctrl-driver |
| 112 | + |
| 113 | +pinctrl-driver主要为pinctrl-core提供pin的操作能力。 |
| 114 | +对于每个具体的SoC,管理方式肯定不同,所以对应到pinctrl-driver上,其实现方式可能会略有不同,但是,所有的pinctrl-driver都是为了达到同一个目标, |
| 115 | +那就是把系统所有的pin信息,以及对于pin的控制接口,实例化成pinctrl_desc,并将pinctrl_desc注册到pinctrl-core中。 |
| 116 | + |
| 117 | +底层的pinctrl-driver对于系统pin的管理是通过 function 和 group 实现的。 |
| 118 | + |
| 119 | +下面解释一下function和group的概念, |
| 120 | +解释之前需要提供一下pinctrl的DTS描述,对于DTS不是很熟悉的可以参考DTS相关的文章: |
| 121 | + |
| 122 | +下面的dts来自于Rockchip 3288的pinctrl配置dts,基于这个DTS,介绍一下pinctrl的 function 和 group 的概念: |
| 123 | +/ { |
| 124 | +pinctrl: pinctrl@ff770000 { |
| 125 | + compatible = "rockchip,rk3288-pinctrl"; |
| 126 | + reg = <0xff770000 0x140>, |
| 127 | + <0xff770140 0x80>, |
| 128 | + <0xff7701c0 0x80>; |
| 129 | + reg-names = "base", "pull", "drv"; |
| 130 | + #address-cells = <1>; |
| 131 | + #size-cells = <1>; |
| 132 | + ranges; |
| 133 | + |
| 134 | + gpio0: gpio0@ff750000 { |
| 135 | + compatible = "rockchip,rk3288-gpio-bank0"; |
| 136 | + reg = <0xff750000 0x100>, |
| 137 | + <0xff730084 0x0c>, |
| 138 | + <0xff730064 0x0c>, |
| 139 | + <0xff730070 0x0c>; |
| 140 | + reg-names = "base", "mux_bank0", "pull_bank0", "drv_bank0"; |
| 141 | + interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; |
| 142 | + clocks = <&clk_gates17 4>; |
| 143 | + |
| 144 | + gpio-controller; |
| 145 | + #gpio-cells = <2>; |
| 146 | + |
| 147 | + interrupt-controller; |
| 148 | + #interrupt-cells = <2>; |
| 149 | + }; |
| 150 | + ...... |
| 151 | + gpio0_i2c0 { |
| 152 | + i2c0_sda:i2c0-sda { |
| 153 | + rockchip,pins = <I2C0PMU_SDA>; |
| 154 | + rockchip,pull = <VALUE_PULL_DISABLE>; |
| 155 | + rockchip,drive = <VALUE_DRV_DEFAULT>; |
| 156 | + //rockchip,tristate = <VALUE_TRI_DEFAULT>; |
| 157 | + }; |
| 158 | + |
| 159 | + i2c0_scl:i2c0-scl { |
| 160 | + rockchip,pins = <I2C0PMU_SCL>; |
| 161 | + rockchip,pull = <VALUE_PULL_DISABLE>; |
| 162 | + rockchip,drive = <VALUE_DRV_DEFAULT>; |
| 163 | + //rockchip,tristate = <VALUE_TRI_DEFAULT>; |
| 164 | + }; |
| 165 | + |
| 166 | + i2c0_gpio: i2c0-gpio { |
| 167 | + rockchip,pins = <FUNC_TO_GPIO(I2C0PMU_SDA)>, <FUNC_TO_GPIO(I2C0PMU_SCL)>; |
| 168 | + rockchip,drive = <VALUE_DRV_DEFAULT>; |
| 169 | + }; |
| 170 | + }; |
| 171 | + |
| 172 | +group: |
| 173 | + 所谓的group,如上dts中的i2c0_sda:i2c0-sda,表示一组具有相同功能的pins, |
| 174 | + 在定义pins的同时,还会提供对于每个pin的电气特性的配置,如上下拉电阻、驱动能力等。 |
| 175 | +function: |
| 176 | + 所谓的function,如上dts中的gpio0_i2c0,表示一种功能标识。每个function可以包括一个或若干个group。 |
| 177 | + 对于每个SOC,function应该是全局唯一的。 |
| 178 | + |
| 179 | + |
| 180 | +底层的pinctrl-driver会在驱动的xxxx_probe函数中,将DTS定义的pinctrl关于function和group的配置,转换为pinctrl_desc中的数据属性, |
| 181 | +同时将pinctrl_desc中的对于pin相关操作的回调函数pctlops、pmxops、confops进行初始化,然后将pinctr_desc注册到pinctrl-core中。 |
| 182 | +之后,pinctrl-driver所要做的工作就是静静的等待pinctrl-core的Love Call。 |
| 183 | + |
| 184 | +至于,pinctrl-driver如何转化pin信息以及pinctrl_desc的抽象接口的具体实现,每个SoC不相同,所以只能去参考每个SOC具体的底层回调函数pctlops、pmxops、confops。。。 |
| 185 | + |
| 186 | + |
| 187 | +1.3. pinctrl-client(具体的设备驱动) |
| 188 | +具体到使用系统pin资源的设备驱动程序,pinctrl-core主要为其提供2种能力: |
| 189 | + 1.隶属于本设备的function的配合能力; |
| 190 | + 2.GPIO子系统对于GPIO的配置能力; |
| 191 | + |
| 192 | + |
| 193 | + 1.2节中描述了pinctrl相关的DTS中的function和group的配置,对于具体的设备驱动,如何使用这些配置信息呢? |
| 194 | + 还是以一个具体设备的DTS配置为例说明问题,DTS配置如下: |
| 195 | + |
| 196 | +i2c0: i2c@ff650000{ |
| 197 | + compatible = "rockchip,rk30-i2c"; |
| 198 | + reg = <0xff650000 0x1000>; |
| 199 | + interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>; |
| 200 | + #address-cells = <1>; |
| 201 | + #size-cells = <0>; |
| 202 | + pinctrl-names = "default", "gpio"; |
| 203 | + pinctrl-0 = <&i2c0_sda &i2c0_scl>; //"default"状态时的 function 和 group |
| 204 | + pinctrl-1 = <&i2c0_gpio>; //"gpio" 状态时的 function 和 group |
| 205 | + gpios = <&gpio0 GPIO_B7 GPIO_ACTIVE_LOW>, <&gpio0 GPIO_C0 GPIO_ACTIVE_LOW>; |
| 206 | + clocks = <&clk_gates10 2>; |
| 207 | + rockchip,check-idle = <1>; |
| 208 | + status = "disabled"; |
| 209 | + }; |
| 210 | + |
| 211 | +上面是关于i2c0控制器的DeviceTree配置信息,我们关心的是下面的配置信息: |
| 212 | + |
| 213 | + pinctrl-names = "default", "gpio"; |
| 214 | + pinctrl-0 = <&i2c0_sda &i2c0_scl>; |
| 215 | + pinctrl-1 = <&i2c0_gpio>; |
| 216 | + |
| 217 | +pinctrl-names表示i2c0控制器所处的两种状态,称为pin state, 即:default、gpio; |
| 218 | + 其中,pinctrl-0对应于 defaut 状态下 其关心的function 和 group, |
| 219 | + 类似,pinctrl-1对应于 gpio 状态下 其关心的function 和 group。 |
| 220 | + |
| 221 | +pinctrl-names所列出的各个状态,与系统电源管理模块的联系比较紧密, |
| 222 | +由于电源管理的需要,系统可能处于不同的工作状态,相应的设备驱动提供pins的不同的工作状态, |
| 223 | +其目的为了降低系统整体功耗,达到省电的需求,这中需求在消费电子产品中尤为重要。 |
| 224 | + |
| 225 | +一般情况下,各个xxx-core-driver,例如i2c-core、spi-core会在调用设备驱动程序的probe()初始化函数之前,将设备的工作状态设定为default状态。 |
| 226 | +pinctrl-core的consumer.h文件(include/linux/pinctrl/consumer.h)文件提供了配置pin state的接口函数,其原型如下: |
| 227 | + |
| 228 | +extern struct pinctrl * __must_check pinctrl_get(struct device *dev); |
| 229 | +extern void pinctrl_put(struct pinctrl *p); |
| 230 | +extern struct pinctrl_state * __must_check pinctrl_lookup_state(struct pinctrl *p, const char *name); |
| 231 | +extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s); |
| 232 | +extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev); |
| 233 | +extern void devm_pinctrl_put(struct pinctrl *p); |
| 234 | +extern int pinctrl_pm_select_default_state(struct device *dev); |
| 235 | +extern int pinctrl_pm_select_sleep_state(struct device *dev); |
| 236 | +extern int pinctrl_pm_select_idle_state(struct device *dev); |
| 237 | + |
| 238 | +对于普通的设备驱动程序来说,一般不会使用到上述的接口,在涉及到电源管理,或者子系统驱动程序(i2c-core、spi-core)可能用到上述接口。 |
| 239 | +具体去参考 GPIO 子系统、i2c-core-drvier、spi-core-drive。 |
| 240 | + |
| 241 | + |
| 242 | + |
| 243 | + |
| 244 | +---------------------------------------------------------------------------------------------------------------------- |
| 245 | +B. pinctrl子系统 应用实例 |
| 246 | +---------------------------------------------------------------------------------------------------------------------- |
| 247 | +关于pinctrl是什么,为什么要用pinctrl,源码深度剖析就不赘述 |
| 248 | + |
| 249 | +下面我介绍一下如何去使用内核中的pinctrl子系统,以device tree设备树为例。 |
| 250 | + |
| 251 | +当你需要控制某些pin的时候,你首先要在device tree中去按照pinctrl的规则去描述它,然后才能在具体的Device Driver中去使用它: |
| 252 | +------------------ |
| 253 | +案例1: |
| 254 | +------------------ |
| 255 | +xxx这个设备要用到 gpg0_1 这个 pin 的 TE_DECON_INT 功能,并分别将这两个状态取了个名字turnon_tes和turnoff_tes. 这个名字是随便起的。 |
| 256 | +重点是看 pinctrl-0 和 pinctrl-1, |
| 257 | +根据示例,它们分别引用了disp_teson和disp_tesoff这两个节点(phandle方式)。 |
| 258 | + |
| 259 | +xxx { |
| 260 | + .... |
| 261 | + pinctrl-names = "turnon_tes", "turnoff_tes"; //两个状态 |
| 262 | + pinctrl-0 = <&disp_teson>; //它里面就会有function,group |
| 263 | + pinctrl-1 = <&disp_tesoff>; //它里面就会有function,group |
| 264 | +}; |
| 265 | + |
| 266 | +两个重要的属性必须要有: |
| 267 | +pins 和 pin-function属性,分别是pin的名字,和要把pin配置成什么功能。还有 gpg0 属于pinctrl_2,所以这个地方引用的是pinctrl_2,而不是其他。 |
| 268 | + |
| 269 | +&disp_teson_pinctrl { //#define disp_teson_pinctrl pinctrl_2 |
| 270 | + disp_teson: disp_teson { |
| 271 | + samsung,pins = disp_teson_pin; //#define disp_teson_pin "gpg0-1" |
| 272 | + samsung,pin-function = <disp_teson_con>;//#define disp_teson_con 2 -- 对应0x2 = TEDECON_INT |
| 273 | + }; |
| 274 | +}; |
| 275 | +&disp_tesoff_pinctrl { |
| 276 | + disp_tesoff: disp_tesoff { |
| 277 | + samsung,pins = disp_tesoff_pin; //#define disp_teson_pin "gpg0-1" |
| 278 | + samsung,pin-function = <disp_tesoff_con>;//#define disp_teson_con 0 |
| 279 | + }; |
| 280 | +}; |
| 281 | + |
| 282 | +那么driver如何去操作这个pin呢? 首先需要熟悉几个内核的API: |
| 283 | + |
| 284 | +1. 获取一个pinctrl句柄,参数是dev,是包含这个pin的device结构体,即xxx这个设备的device |
| 285 | +/** |
| 286 | + * struct devm_pinctrl_get() - Resource managed pinctrl_get() |
| 287 | + * @dev: the device to obtain the handle for |
| 288 | + * |
| 289 | + * If there is a need to explicitly destroy the returned struct pinctrl, |
| 290 | + * devm_pinctrl_put() should be used, rather than plain pinctrl_put(). |
| 291 | + */ |
| 292 | +struct pinctrl *devm_pinctrl_get(struct device *dev) |
| 293 | + |
| 294 | + |
| 295 | +2. 获取这个pin对应pin_state(引脚状态-turnon_tes/turnoff_tes) |
| 296 | +/** |
| 297 | + * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle |
| 298 | + * @p: the pinctrl handle to retrieve the state from |
| 299 | + * @name: the state name to retrieve |
| 300 | + */ |
| 301 | +struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name) |
| 302 | + |
| 303 | +3. 设置引脚为某个stata -- turnon_tes/turnoff_tes |
| 304 | +/** |
| 305 | + * pinctrl_select_state() - select/activate/program a pinctrl state to HW |
| 306 | + * @p: the pinctrl handle for the device that requests configuration |
| 307 | + * @state: the state handle to select/activate/program |
| 308 | + */ |
| 309 | +int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) |
| 310 | + |
| 311 | +------------------------------------ |
| 312 | +具体操作: |
| 313 | +------------------------------------ |
| 314 | +/* 获取pin control state holder 的句柄 */ |
| 315 | +pinctrl = devm_pinctrl_get(dev); |
| 316 | + |
| 317 | +/* 得到名字为turnon_tes和turnoff_tes的对应的pin state */ |
| 318 | +struct pinctrl_state * turnon_tes = pinctrl_lookup_state(pinctrl, "turnon_tes"); |
| 319 | +struct pinctrl_state * turnoff_tes = pinctrl_lookup_state(pinctrl, "turnoff_tes"); |
| 320 | + |
| 321 | +/* 设置名字为turnon_tes这个pinctrl对应引脚(gpg0-1)的pin state,即gpg0_1对应的寄存器位域设置为2 */ |
| 322 | +pinctrl_select_state(pinctrl, turnon_tes)。 |
| 323 | + |
| 324 | +经过以上操作,gpg_1引脚对应的con寄存器的对应的位域被配置成2,即0x2 = TE_DECON_INT功能。 |
| 325 | + |
| 326 | +以此类推,根据此方法也可以设置turnoff_tes的状态。 |
| 327 | + |
| 328 | + |
| 329 | + |
| 330 | +------------------ |
| 331 | +案例2 -- 一个背光灯device需要使用pwm的输出pin: |
| 332 | +------------------ |
| 333 | +device tree: |
| 334 | +背光系统中要用到gpd2_4这个pin的TOUT_0功能和gpd4_3这个pin的输出功能并输出1,需要在backlight这个node中做以下描述,这两个pin只有一个状态(pwm-on),同样,这个名字也是可以随便起的。bl_pwm_ctrl和bl_pwm_en_ctrl分别是对这两个pin的描述。 |
| 335 | + |
| 336 | +backlight { |
| 337 | + ... |
| 338 | + ... |
| 339 | + pinctrl-names = "pwm-on"; |
| 340 | + pinctrl-0 = <&bl_pwm_ctrl @bl_pwm_en_ctrl>; |
| 341 | +}; |
| 342 | + |
| 343 | +/* 这个和上面一样,就不多说了 */ |
| 344 | + |
| 345 | +&bl_pwm_ctrl_pinctrl{ //#define bl_pwm_ctrl_pinctrl pinctrl_2 |
| 346 | +bl_pwm_ctrl: bl_pwm_ctrl { |
| 347 | +samsung,pins = bl_pwm_ctrl_pin; //#define bl_pwm_ctrl_pin "gpd2-4" |
| 348 | +samsung,pin-function = <bl_pwm_ctrl_con>; //#define bl_pwm_ctrl_con 2 |
| 349 | +samsung,pin-pud = <bl_pwm_ctrl_pull>; //#define bl_pwm_ctrl_pull 3 |
| 350 | +samsung,pin-drv = <bl_pwm_ctrl_drv>; //#define bl_pwm_ctrl_drv 0 |
| 351 | +}; |
| 352 | +}; |
| 353 | + |
| 354 | +这个描述比上面多了个pin-val,因为这个引脚不仅要配置成输出功能,还要输出1,所以pin-val = 1。 |
| 355 | + |
| 356 | +&bl_pwm_en_ctrl_pinctrl{ |
| 357 | +bl_pwm_en_ctrl: bl_pwm_en_ctrl { |
| 358 | +samsung,pins = bl_pwm_en_ctrl_pin; //#define bl_pwm_en_ctrl_pin "gpd4-3" |
| 359 | +samsung,pin-function = <bl_pwm_en_ctrl_con>; //#define bl_pwm_en_ctrl_con 1 |
| 360 | +samsung,pin-val = <1>; |
| 361 | +samsung,pin-pud = <bl_pwm_en_ctrl_pull>; |
| 362 | +samsung,pin-drv = <bl_pwm_en_ctrl_drv>; |
| 363 | +}; |
| 364 | +}; |
| 365 | + |
| 366 | +driver的操作: |
| 367 | + |
| 368 | +在backlight的driver的probe中: |
| 369 | + |
| 370 | +struct pinctrl * p = devm_pinctrl_get(&pdev->dev); |
| 371 | +struct pinctrl_state * default_state = pinctrl_lookup_state(p, "pwm-on"); |
| 372 | +pinctrl_select_state(p, default_state); |
| 373 | + |
| 374 | +执行完以上操作,可以发现gpd2_4引脚被配置成了TOUT_0功能,gpd4_3引脚被配置成为了输出功能,并且输出1(高电平)。 |
| 375 | +以上就是pinctrl子系统的应用实例。如果有解释不太正确的地方请指教。 |
| 376 | + |
| 377 | +--------------------- |
0 commit comments