Unable to set I2C4 Alternate function on iMX7

On the board design I am working with we have an external RTC that I am trying to interface with on I2C4. Not having much luck with getting this to work properly. The external RTC that we are using is the M41T0M6F and we are trying to attach to it via I2C4 however the board design is not using the standard pinouts on 194 and 196. The RTC SCL is attached to pin 77 and the SDA is attached to pin 67. To try and accomplish this I modified HKLM\Drivers\Builtin\I2C1 making the following changes.

SclAF → 0x00000003 (3)
SclPin → 0x0000004d (77)
SdaAF → 0x00000004 (4)
SdaPin → 0x00000043 (67)

RTCSync is not working properly. When I look at the IMX7_GPIO Tool. I am seeing that I2C4_SDA is properly mapped to pin 67. But I am not seeing I2C4_SCL mapped to pin 77. I am not seeing it mapped anywhere right now. I was able to map other pins over in testing so I am assuming this issue only effects pin 77. Any ideas would be greatly appreciated.

Hi @GreenMtnDev,

The best way to go here is to change the device tree from Colibri iMX7 instead of changing the driver itself. In the device tree, you can set the right pins and assign the RTC.

You can check the device tree for Colibri iMX7 here: imx7-colibri.dtsi « dts « boot « arm « arch - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

Inside, there is the definition of &i2c4 and the pins you have to change, &pinctrl_i2c4:

....
	pinctrl_i2c4: i2c4-grp {
		fsl,pins = <
			MX7D_PAD_ENET1_RGMII_TD3__I2C4_SDA	0x4000007f
			MX7D_PAD_ENET1_RGMII_TD2__I2C4_SCL	0x4000007f
		>;
	};

	pinctrl_i2c4_recovery: i2c4-recoverygrp {
		fsl,pins = <
			MX7D_PAD_ENET1_RGMII_TD2__GPIO7_IO8	0x4000007f
			MX7D_PAD_ENET1_RGMII_TD3__GPIO7_IO9	0x4000007f
		>;
	};

....

&i2c4 {
	clock-frequency = <100000>;
	pinctrl-names = "default", "gpio";
	pinctrl-0 = <&pinctrl_i2c4>;
	pinctrl-1 = <&pinctrl_i2c4_recovery>;
	scl-gpios = <&gpio7 8 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
	sda-gpios = <&gpio7 9 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;

	status = "disabled";

	/* Atmel maxtouch controller */
	atmel_mxt_ts: touchscreen@4a {
		compatible = "atmel,maxtouch";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_atmel_connector>;
		reg = <0x4a>;
		interrupt-parent = <&gpio2>;
		interrupts = <15 IRQ_TYPE_EDGE_FALLING>;        /* SODIMM 107, INT */
		reset-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>;     /* SODIMM 106, RST */
		status = "disabled";
	};
};

And here it’s an example of an implementation of this RTC you are using:

&i2c4 {
	status = "okay";

	/* M41T0M6 real time clock on carrier board */
	rtc: m41t0m6@68 {
		compatible = "st,m41t0";
		reg = <0x68>;
	};
};

So you will have to change the pins being used inside the Colibri iMX7 and also add the RTC to your device tree. Setting compatible = "st,m41t0"; will make the driver correctly use this device, without changing the driver code itself.

Please, take a look at this article: Pin Multiplexing - Changing Pin Functionalities in the Linux Device Tree | Toradex Developer Center

Let me know if you have any questions about that.

Best Regards,
Hiago.

Hiago,

Thank you for the quick response. I should have been more clear I am working with WEC2013. Is there an equivalent change that I can make from there?

Hi @GreenMtnDev,

Oh ok, sorry about that. So I’ll let @alex.tx answer this question then.

Best Regards,
Hiago.

Please check this articles:

Hi Alex -

I have been working on other areas of our software…now finally circling back on the RTC. As I stated above I have an external RTC(M41T0M6F) that is hooked up I2C4. We are not using the default pins of 194 and 196 but rather 67 and 77. I have modified the boot config with the block config
[colibripin_67] altfn=4 [colibripin_77] altfn=3

This seems to have worked fine as I see the the following in the iMX7 GPIO V1.2 tool:
GPIO Pin Name Altfn Name Direction Level SODIMM.MXM3 Front/Back EvalLoc
11 GPIO… i2c4.I2C4_SDA - - 67# Front X10, 30
116 ECSPi2… GPIO Input 1 67# Front X10, 30
.
.
176 SAI1_RXFS i2c4_SCL - - 77 Front X22, 22

However the RTCSync is still not synchronizing properly. I am running WEC2013 with the default RTCSync settings. Would have assumed this would have addressed my issue but now dice. Would you have any insights you could offer on this. We are approaching release of this product and this is the final hurdle I need to clear.

Thank you very much!

It should be noted that some of the pins are multiplexed; that is, there is more than one i.MX 7 SoC
pin connected to one SODIMM pin. For example, ECSPI2_SCLK and GPIO1_IO11 are both
connected to SODIMM pin 67. Care should be taken to ensure that multiplexed pins are tri-stated
when they are not being used (e.g. if i.MX 7 pin A and pin B are tied to SODIMM pin 1, then if i.MX
7 pin A is being driven, pin B should be tri-stated). Additional information can be found in chapter
4.1: Function Multiplexing.

Also

Multiplexing for a specific driver

To configure multiplexing for a specific driver you have to put the “Pinout_*” entries under its configuration key. For example to change multiplexing of UART for all modules you can add:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\CoM2\Pinout_Default]
entry in the registry and configure the corresponding pins.
Adding a Pinout entry will prevent the driver from applying the default pin multiplexing configuration so even if you just need to change the multiplexing of a single pin you’ll have to specify the multiplexing for all the other pins managed by the driver.
Setting the wrong multiplexing may prevent the driver from working and may lead to issues.
The new multiplexing will be applied only after you reboot your device.

Hello Alex,

Thank you for the above information. The information I found under the multiplexing chapter mentions adding a DoMultiplexing DWORD flag and setting it to 1.

I have added this to HKLM\Drivers\BuiltIn\I2C1\Pinout_Default. That covers GPIO11 → i2c4.I2C4_SDA quite well. However I am looking to define the same for ECSPI2_SCLK → GPIO - Where should this be defined?

The other option is can I just turnoff multiplexing on the I2C1 and somehow map the ECSPI2_SCLK to AltFn-8. Which is nothing. Then multiplexing would not be required, right?

Thanks,
Dan

Could you post a snippet of RTCsync code which is failing (and also note a returned error code)?

I am using the default RTCSync supplied in the Toradex image. So I am unable to give you the error code. I was under the impression that since I was using the M41T0M6F RTC that this did not require a custom version of the RTCSync.

Up until now I have been testing this by Modifying the system date time - Either via the Control Panel or via C++ code. It was my impression that this would call RTCSync automatically. Then I would reboot the device to see if the clock value could be extracted back out.

Are my testing assumptions correct?

Thanks,
Dan

Hi Alex,

I have removed the rtcsysnc and the driver name for i2c1 from the registry. When I re-open the iMX7 GPIO V1.2 tool I do not see anything assigned to i2c4. In my code I have added the following block.

I2c_GetVersion(&ver);
i2c = I2c_Init(L"I2C1");
BOOL res1 = I2c_SetConfigInt(i2c, L"ioScl", 0x4D, StoreVolatile);
BOOL res2 = I2c_SetConfigInt(i2c, L"ioSda", 0x43, StoreVolatile);
if (i2c == NULL)
printf(“Error in I2c_Init()\r\n”);

// Open the i2c port
I2c_Open(i2c);
I2c_SetConfigInt(i2c, L"SlaveAddr", 0x68, StoreVolatile);

In this scenario - res1 and res2 are both set to FALSE, resulting in i2c being set to the default 194 and 196 after I2C_open.

Any other options I might be able to try.

-Dan

Hi Alex,

Found something mentioned on the board mentioning creating uIo objects before calling I2c_SetConfigInt.

That looks like this now.

	uIo ioScl = COLIBRI_PIN(77);
	uIo ioSda = COLIBRI_PIN(67);
	BOOL res1 = I2c_SetConfigInt(i2c, TEXT("ioSda"), (DWORD)&ioSda, StoreVolatile); 
	BOOL res2 = I2c_SetConfigInt(i2c, TEXT("ioScl"), (DWORD)&ioScl, StoreVolatile);

Note: This made no difference - res 1 and res2 are still closed.

-Dan

The Colibri imxy pins 77 and 67 are I2C4 alternative pins. So you need to init I2C4 port instead of I2C1. For the same reason you can’t use RTCsync with pins 67/77 since I2C1 is hardcoded there for RTC chip communication. It is possible to purchase the source code of the RTCSync tool, in order to adjust it for your configuration. Or you can write your own version and use it instead.

Thanks Alex. Did this recently change?

I started down this path when I read the quote below.

"Pins 96 and 75 belong to the physical i.mx7-i2c instance i2c4. This is the same instance which is available on pins 194 and 196 by default (The default i2c pins for any Colibri module). The external RTC on the Evaluation Board is connected to these pins.

Because it is the default instance, we call it [HKLM\Drivers\Builtin\I2C 1] in the registry (sorry for the potential confusion)."

@Andy.tx had written the above a few years back in this thread.

Is this info no longer true…or is it only talking about i2c4 on pins 194 and 196?

Thanks

Hi @GreenMtnDev ,

Sorry for all the confusion… i will try to clarify:

First of all as you mentioned there is a Logical I2C number and a HW Instance I2C number.
We use Logical I2C numbers so I2C is more portable across different SOCs.
So Logical I2C1 is HW I2C4 on iMX7

Next is the issue with selecting an alternate pinmuxing other than the default 196/194:
The RTCSync tool does not call any I2c_SetConfigInt() with "ioSda"or “ioScl”, so the library will init using default ports.
The way you tried to call I2c_SetConfigInt() is wrong… this is the right way:

uIo ioScl = COLIBRI_PIN(77);
uIo ioSda = COLIBRI_PIN(67);
res1 = I2c_SetConfigInt(i2c, L"ioScl", ioScl.GenericDefinition, StoreVolatile);
res2 = I2c_SetConfigInt(i2c, L"ioSda", ioSda.GenericDefinition, StoreVolatile);

NOTE: if you use StoreToRegistry instead of StoreVolatile, those settings are stored to the registry and will be applied for any library user that does not explicitly set those configs (will then make the standard RTCSync work on the alternate pins)

Registry settings are stored under:

[HKLM\SOFTWARE\Toradex\I2C1]

There is one last thing that makes things more complicated. iMX7 uses a driver for I2c (HKLM\Drivers\BuiltIn\I2C1). The library is basically a wrapper around the driver.
Normally the I2C drivers are not loaded (missing “Dll” value) and are only loaded by the library when needed. Before loading the driver the library will set some additional registry entries “SclPin”/“SclAf”/“SdaPin”/“SdaAf” if the pinmuxing is not standard.
But in case the driver is already loaded (for example RTCSync already triggered the load), and a different pinmuxing is needed, the I2c_Open() will fail.
So make sure that you don’t save the registry with a valid “Dll” entry for the I2C1 driver as otherwise you cannot change the pinmux anymore. Also you need to temporary disable RTCSync from HKLM\init\launch48 until you once save your desired pinmux by calling I2c_SetConfig() with StoreToRegistry flag.

Hope i explained it well enough.

Thank you for the explanation. This makes sense. We were never using pins 194 and 196 in our current design so we ended up rerouting the RTC to pins 194 and 196. This solved our issue. But good to know in the future.

Thanks