iMX6 Pad Mux and Pad Control - FrankBau/meta-marsboard-bsp GitHub Wiki
The electrical behaviour of most iMX6 pads can be controlled by pad control registers. This is described in full detail in the "IOMUX Controller (IOMUXC)" chapter of the iMX6 Reference Manual. There are also docs for Linux: http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt
Control capabilities include:
- optional hysteresis (Schmitt-Trigger input)
- optional pull-down or pull-up resistors (PUS, PUE, PKE)
- optional open-drain output (ODE)
- pad speed and slew-rate settings (SPEED, SRE)
- output driver strength (DSE)
Here is an excerpt of Frescale's iomux-v3.h defining the individual values:
#define PAD_CTL_HYS (1 << 16)
#define PAD_CTL_PUS_100K_DOWN (0 << 14)
#define PAD_CTL_PUS_47K_UP (1 << 14)
#define PAD_CTL_PUS_100K_UP (2 << 14)
#define PAD_CTL_PUS_22K_UP (3 << 14)
#define PAD_CTL_PUE (1 << 13)
#define PAD_CTL_PKE (1 << 12)
#define PAD_CTL_ODE (1 << 11)
#define PAD_CTL_SPEED_LOW (1 << 6)
#define PAD_CTL_SPEED_MED (2 << 6)
#define PAD_CTL_SPEED_HIGH (3 << 6)
#define PAD_CTL_DSE_DISABLE (0 << 3)
#define PAD_CTL_DSE_240ohm (1 << 3)
#define PAD_CTL_DSE_120ohm (2 << 3)
#define PAD_CTL_DSE_80ohm (3 << 3)
#define PAD_CTL_DSE_60ohm (4 << 3)
#define PAD_CTL_DSE_48ohm (5 << 3)
#define PAD_CTL_DSE_40ohm (6 << 3)
#define PAD_CTL_DSE_34ohm (7 << 3)
#define PAD_CTL_SRE_FAST (1 << 0)
#define PAD_CTL_SRE_SLOW (0 << 0)
The Device Tree allows to express pad multiplexing and pad control.
Example:
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
hog {
pinctrl_hog: hoggrp {
fsl,pins = <
/* gpio-leds */
MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x80000000
MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000
/* J11 pins 32, 34, 36, 38 */
MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 8
MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 8
MX6QDL_PAD_KEY_COL1__GPIO4_IO08 8
MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 8
>;
};
};
};
Lets take pin 38 of MarS Board header J11 as an example. In the MarS Board schematics, this pin is connected to net I2C1_SDA
. The other end of this net is iMX6 pad CSI0_DAT8
. Lets say, for example, we don't want to use neither the I²C nor the CSI (display) function of this pad. It should function as a general purpose output. This is done by the line MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 8
.
The first macro MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26
does the pad multiplexing. The substring CSI0_DAT8
after the prefix MX6QDL_PAD_
and before the double underscore refers to the iMX6 pad name and the substring after the double underscore refers to the desired pad function: GPIO5_IO26
.
All these mystical macros are defined in file imx6q-pinfunc.h
in the build/tmp/work/marsboard-poky-linux-gnueabi/linux-marsboard/3.10.53-r0/git/arch/arm/boot/dts
folder.
The number 8
after the pad muxing macro refers to the pad control. To understand this value, you may check the iMX6 Reference Manual for register IOMUXC_SW_PAD_CTL_PAD_CSI0_DATA08
. The 8
is a bitwise composition of the following:
- (0<<0) : slow slew rate
- (1<<3) : output drive strength of 150 Ohm at 3.3 V
- (0<<6) : low speed (<50 MHz)
Besides the iMX6 Reference Manual there is a recent application note "AN5078":http://cache.freescale.com/files/32bit/doc/app_note/AN5078.pdf describing the versatile pad control options.
There are two special values:
- 0x80000000 means: pad already configured, e.g. by the boot loader
- Bit 30 set to 1 means: software input on (SION) whcih means that the logical value of an output can be read back (see this post for discussion: http://permalink.gmane.org/gmane.linux.ports.arm.kernel/295260)
If you want to use, say the I²C pad function for pin 38 of MarS Board header J11, things are easier. Many pad settings are already define in the include file imx6qdl.dtsi
(same folder as dts: build/tmp/work/marsboard-poky-linux-gnueabi/linux-marsboard/3.10.53-r0/git/arch/arm/boot/dts/
). Lets check that out:
The following device tree node describes the I2C1 hardware block inside the iMX6 SoC and two compatible device ids in the compatible line:
i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>;
interrupts = <0 36 0x04>;
clocks = <&clks 125>;
status = "disabled";
};
Further down, in the &iomuxc block are the pad configurations:
&iomuxc {
...
i2c1 {
pinctrl_i2c1_1: i2c1grp-1 {
fsl,pins = <
MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
>;
};
pinctrl_i2c1_2: i2c1grp-2 {
fsl,pins = <
MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
>;
};
};
The pad control value is different here (0x4001b8b1
) because, among others, I2C requires open-drain outputs (Bit 11 set).
Luckily, the second definition labelled pinctrl_i2c1_2
matches the Mars Board schematics. Pad muxing and pad control are already defined. In this case, you have to add only a few lines to your .dts file:
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_2>;
status = "okay";
};
In other cases, no appropriate pad configuration is pre-defined. So you need to roll our own as it was the case for the GPIO pads above. Check the .dts of similar boards for known-good templates.
Note: The driver i2c-imx.c
in folder build/tmp/work/marsboard-poky-linux-gnueabi/linux-marsboard/3.10.53-r0/git/drivers/i2c/busses
is compiled into the Linux kernel (see Kernel config) and declares in its struct of_device_id i2c_imx_dt_ids
that it is compatible with fsl,imx21-i2c
devices. Therefore, the Linux kernel loads it and your newly defined I2C device is functional.