Making Rockchip IO domains dependency from other devices explicit
Quentin Schulz
quentin.schulz at theobroma-systems.com
Tue Jun 14 05:41:06 PDT 2022
Hi all,
We have hit an issue for a product for which will send patches in the
next few months and I'm asking for guidance on how to properly fix this
in upstream Linux kernel (we are currently carrying a patch in our
downstream U-Boot bootloader instead).
On some Rockchip SoCs, some SoC pins are split in what are called IO
domains.
An IO domain is supplied power externally, by regulators from a PMIC for
example. This external power supply is then used by the IO domain as
"supply" for the IO pins if they are outputs.
Each IO domain can configure which voltage the IO pins will be operating
on (1.8V or 3.0V). It is unclear if there's a voltage divider in IO
domains for lowering from whatever the regulator is supplying to the
supported 3.0V or 1.8V.
There already exists an IO domain driver for Rockchip SoCs[1]. This
driver allows to explicit the relationship between the external power
supplies and IO domains[2]. This makes sure the regulators are enabled
by the Linux kernel so the IO domains are supplied with power.
This driver is a regulator consumer and does not offer any other
interface for device dependency.
Currently, the IO pin 1.8/3.0V selection is made based on the voltage
supported by the regulator attached to a specific IO domain.
And this is where the issue lies. The product has a camera sensor which
didn't even appear on i2c until we figured out that its MCLK was
actually oscillating between 0 and ~150mV. It appeared that after a soft
reboot, the camera sensor would then appear on i2c. The driver of this
camera sensor attempts an I2C transfer to check its ID, which fails the
probe of the driver because the IO domain of the MCLK pin is not
supplied with power yet/correctly configured (the io-domains driver
probes after the camera driver). After configuring the IO domain
correctly in the bootloader prior to booting the Linux kernel, the
camera sensor is now working just fine.
In order to have my camera sensor working and not rely on what the
bootloader set before Linux boots, I need to have the IO domain(s)
correctly configured before the camera sensor driver probes. The issue
is how to represent this dependency in the device tree.
It was suggested to me that we could use the power subsystem and use
xxx-supply in DT for this, by making the io-domains driver expose a
regulator per IO domain. This works fine if the IO pin connected to the
device is already a power supply for that device, so we can just make
this gpio-regulator depend on the regulator of the IO domain this IO pin
is from. If it is not a regulator, this would mean we need to modify
drivers to add a new power supply DT property for each driver. This can
blow up pretty quickly and require, IMO, non-generic changes to driver
to support SoC "quirks". Such would be the case for us, because I'd need
to add this power supply DT property to the clock driver so that when
the clock driver is probed, the regulators for the IO domains of the
clocks exposed on IO pins are actually also enabled and the IO domains
properly configured.
So I think the best way would be to have something transparent to the
driver. Something handled on the subsystem level?
Looking a bit in the other kernel drivers to fish for inspiration and I
stumbled upon pinctrl-sunxi driver.[3][4] This driver allows to specify
a regulator as power supply per GPIO bank and will enable/disable it if
there's a new user/none. The user would just need to add
pinctrl-0/pinctrl-names to the device tree node of the device to both
configure the GPIO correctly and enable the regulator for the bank this
GPIO is attached to.
Technically, since the pinctrl subsystem has much of its behavior for
consumers abstracted, this would make it a good fit for doing things
transparently for drivers. The plan would be to have the IO domain
driver expose pinctrl configuration nodes that are linked to a specific
IO domain which would enable the appropriate regulator. I feel this is
quite a reach/abuse of the pinctrl subsystem. Since the IO domain
registers actually are configurable for 3.0V/1.8V, maybe this is
actually "pin control" in the broad sense?
My suggestion would look like the following (based on rk3399-puma.dtsi):
'''
&io_domains {
status = "okay";
bt656-supply = <&vcc_1v8>;
audio-supply = <&vcc_1v8>;
sdmmc-supply = <&vcc_sd>;
gpio1830-supply = <&vcc_1v8>;
pinctrl_bt656_3v0: pinctrl-bt656-3v0 {
pins = "bt656";
function = "3v0";
};
pinctrl_bt656_1v8: pinctrl-bt656-1v8 {
pins = "bt656";
function = "1v8";
};
};
&camera {
[...]
pinctrl-0 = <&pinctrl_bt656_3v0>;
pinctrl-names = "default";
};
'''
We could also do checks in the driver so that the selected pinmux
matches what the HW is capable of (e.g. if an 1.8V regulator supplies
the IO domain and the pinctrl is requested for 3.0V it should fail). But
that's just implementation details.
I'm looking for an upstreamable solution, would that fit the criteria?
Does anyone have something else to suggest or some feedback to give?
Feel free to correct me on my definitions or assumptions :)
I've added some contributors of this driver in Cc, I hope you don't mind.
Thanks,
Quentin
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/soc/rockchip/io-domain.c
[2]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/power/rockchip-io-domain.yaml
[3]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/pinctrl/sunxi/pinctrl-sunxi.c
[4]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/pinctrl/allwinner,sun4i-a10-pinctrl.yaml
More information about the Linux-rockchip
mailing list