* Re: [PATCH v2 phy-next 01/15] phy: lynx-28g: reject probing on devices with unsupported OF nodes
From: Vladimir Oltean @ 2026-06-02 14:52 UTC (permalink / raw)
To: sashiko-reviews; +Cc: vkoul, linux-phy, olteanv, neil.armstrong
In-Reply-To: <20260529173544.908FE1F00893@smtp.kernel.org>
On Fri, May 29, 2026 at 05:35:43PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] The lynx_28g_xlate callback can return NULL for uninitialized PHY lanes, leading to a NULL pointer dereference in the PHY framework.
> - [High] The PHY device retains a pointer to an OF child node after its reference count has been dropped, leading to a potential Use-After-Free.
> --
>
> commit 74be4f3f82272eac244d345f53d8340e9a230084
> Author: Vladimir Oltean <vladimir.oltean@nxp.com>
>
> phy: lynx-28g: reject probing on devices with unsupported OF nodes
>
> This patch fixes a crash triggered via the driver_override mechanism when
> of_device_get_match_data() returns NULL for a device with a different
> compatible string. It adds a check to return -ENODEV if the match data
> is missing.
>
> > diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
> > index 92bfc5f65e0b8..4461b47a16ad6 100644
> > --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
> > +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
> > @@ -1477,6 +1477,9 @@ static int lynx_28g_probe(struct platform_device *pdev)
> >
> > priv->dev = dev;
> > priv->info = of_device_get_match_data(dev);
> > + if (!priv->info)
> > + return -ENODEV;
> > +
> > dev_set_drvdata(dev, priv);
> > spin_lock_init(&priv->pcc_lock);
> > INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
>
> [Severity: High]
> This isn't a bug introduced by this patch, but does this function leave the
> PHY device with a pointer to a freed child node later in the probe process?
>
> Further down in lynx_28g_probe():
>
> for_each_available_child_of_node(dn, child) {
> ...
> err = lynx_28g_probe_lane(priv, reg, child);
> ...
>
> The for_each_available_child_of_node() macro automatically handles
> reference counting for the child node.
>
> When lynx_28g_probe_lane() creates the PHY, phy_create() stores this
> child node in phy->dev.of_node, but it does not call of_node_get() to
> acquire an additional reference.
>
> Once the loop advances, the iterator automatically calls of_node_put(),
> dropping the reference. If the node is later dynamically freed, such as
> during a DT overlay unload, could this cause a use-after-free when
> phy->dev.of_node is accessed?
>
This is a problem within phy_create() not calling of_node_get() when
assigning phy->dev.of_node. It is out of scope for this series.
> [Severity: High]
> This is a pre-existing issue, but can the xlate callback return NULL for
> uninitialized PHY lanes and cause a crash in the PHY framework?
>
> If a requested lane index is within bounds but the lane was not probed
> (due to a missing subnode in the device tree), priv->lane[idx].phy remains
> NULL and is returned directly by lynx_28g_xlate().
>
> When this NULL is passed to of_phy_get() by _of_phy_get():
>
> drivers/phy/phy-core.c:of_phy_get() {
> ...
> if (IS_ERR(phy))
> return phy;
>
> if (!try_module_get(phy->ops->owner))
> ...
> }
>
> Since IS_ERR(NULL) evaluates to false, it proceeds to dereference the NULL
> pointer via phy->ops->owner. Should the callback return ERR_PTR(-ENODEV)
> instead for missing lanes?
Yeah, ok, _of_phy_get() does not work when phy_provider->of_xlate()
returns NULL, it needs to be an error-encoded pointer instead.
Will add one patch for v3.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Incorrect reply address with b4 relay [was Re: [PATCH v6 2/2] phy: add basic support for NXPs TJA1145 CAN transceiver]
From: Rob Herring @ 2026-06-02 16:02 UTC (permalink / raw)
To: sashiko-reviews
Cc: Dimitri Fedrau via B4 Relay, olteanv, vkoul, neil.armstrong,
linux-phy, devicetree, conor+dt
In-Reply-To: <20260602083856.E92081F00898@smtp.kernel.org>
Sashiko devs,
It looks like sashiko replies to b4 relay submissions don't get sent to
the author's email and instead go to the relay's email (devnull). Here's
the header of the reply:
> Date: Tue, 02 Jun 2026 08:38:56 +0000
> From: sashiko-bot@kernel.org
> To: Dimitri Fedrau via B4 Relay <devnull+dimitri.fedrau.liebherr.com@kernel.org>
> Cc: olteanv@gmail.com, vkoul@kernel.org, neil.armstrong@linaro.org, linux-phy@lists.infradead.org, devicetree@vger.kernel.org, conor+dt@kernel.org, robh@kernel.org
> Subject: Re: [PATCH v6 2/2] phy: add basic support for NXPs TJA1145 CAN transceiver
> Message-Id: <20260602083856.E92081F00898@smtp.kernel.org>
On Tue, Jun 02, 2026 at 08:38:56AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] If setting the CAN operating mode fails during `tja1145_phy_power_on`, the PHY hardware is left in normal operating mode without rolling back to standby mode.
> --
>
> commit 4b999361552fc4af356fbf9fbd3b1ca5f2dd59bf
> Author: Dimitri Fedrau <dimitri.fedrau@liebherr.com>
>
> phy: add basic support for NXPs TJA1145 CAN transceiver
>
> This commit adds basic driver support for the NXP TJA1145 CAN transceiver.
> It enables bringing the PHY up or down by switching between normal and
> standby modes using SPI commands.
>
> > diff --git a/drivers/phy/phy-nxp-tja1145.c b/drivers/phy/phy-nxp-tja1145.c
> > new file mode 100644
> > index 0000000000000..1e8bd169743ab
> > --- /dev/null
> > +++ b/drivers/phy/phy-nxp-tja1145.c
>
> [ ... ]
>
> > +static int tja1145_phy_power_on(struct phy *phy)
> > +{
> > + struct regmap *map = phy_get_drvdata(phy);
> > + int ret;
> > +
> > + /*
> > + * Switch operating mode to normal which is the active operating mode.
> > + * In this mode, the device is fully operational.
> > + */
> > + ret = regmap_update_bits(map, TJA1145_MODE_CTRL, TJA1145_MODE_CTRL_MC,
> > + TJA1145_MODE_CTRL_NORMAL);
> > + if (ret)
> > + return ret;
> > +
> > + /*
> > + * Switch to CAN operating mode active where the PHY can transmit and
> > + * receive data.
> > + */
> > + return regmap_update_bits(map, TJA1145_CAN_CTRL, TJA1145_CAN_CTRL_CMC,
> > + TJA1145_CAN_CTRL_ACTIVE);
> > +}
>
> [Severity: Medium]
> If the second regmap_update_bits call fails to set TJA1145_CAN_CTRL, does
> this leave the hardware in normal mode without reverting to standby?
>
> Because tja1145_phy_power_on would return an error here, the PHY framework
> will not consider the PHY powered on and will not invoke
> tja1145_phy_power_off later. Could this result in the hardware being
> permanently left in a higher-power state?
>
> Should the driver intercept this error and attempt to roll back
> TJA1145_MODE_CTRL to TJA1145_MODE_CTRL_STBY before returning?
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260602-tja1145-support-v6-0-0e0ffc8ee63d@liebherr.com?part=2
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v2 phy-next 13/15] dt-bindings: phy: lynx-10g: initial document
From: Conor Dooley @ 2026-06-02 17:10 UTC (permalink / raw)
To: Vladimir Oltean
Cc: linux-phy, Ioana Ciornei, Vinod Koul, Neil Armstrong,
Tanjeff Moos, linux-kernel, devicetree, Conor Dooley,
Krzysztof Kozlowski, Rob Herring
In-Reply-To: <20260529171509.1163787-14-vladimir.oltean@nxp.com>
[-- Attachment #1.1: Type: text/plain, Size: 5088 bytes --]
On Fri, May 29, 2026 at 08:15:07PM +0300, Vladimir Oltean wrote:
> Add a schema for the 10G Lynx SerDes. This is very similar to the modern
> form of the 28G Lynx SerDes, which is very much the intention.
>
> We allow both forms of #phy-cells = <1> in the top-level provider
> and #phy-cells = <0> in the per-lane provider for more flexibility to
> consumers, and because the kernel code is shared with the 28G Lynx which
> already has that support for compatibility reasons.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> Cc: devicetree@vger.kernel.org
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Rob Herring <robh@kernel.org>
>
> v1->v2:
> - move patch later in series, right before driver
> - deliberately ignoring this Sashiko feedback:
> https://lore.kernel.org/linux-phy/20260529125017.ifqunh52gdzhthdg@skbuf/
> ---
> .../devicetree/bindings/phy/fsl,lynx-10g.yaml | 131 ++++++++++++++++++
> 1 file changed, 131 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml
>
> diff --git a/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml b/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml
> new file mode 100644
> index 000000000000..993f076bba4e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml
> @@ -0,0 +1,131 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/fsl,lynx-10g.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Freescale Lynx 10G SerDes PHY
> +
> +maintainers:
> + - Vladimir Oltean <vladimir.oltean@nxp.com>
> +
> +description:
> + The 10G Lynx is a multi-protocol SerDes block which handles networking, PCIe,
> + SATA and other high-speed interfaces. It is present on most QorIQ and
> + Layerscape SoCs. The register map is common, but the integration is
> + SoC-specific, with the differences consisting in register endianness, the
> + number of lanes, protocol converters available per lane and their location in
> + the PCCR registers. Some SoCs have multiple SerDes blocks and those differ in
> + their protocol capabilities per lane.
> +
> +properties:
> + compatible:
> + description:
> + There is intentionally no generic fsl,lynx-10g compatible string due to
> + the hardware inability to report its capabilities, despite having a
> + common register map.
I think you can probably drop this from the diff, and put it in the
commit message.
> + enum:
> + - fsl,ls1028a-serdes
> + - fsl,ls1046a-serdes1
> + - fsl,ls1046a-serdes2
> + - fsl,ls1088a-serdes1
> + - fsl,ls1088a-serdes2
> + - fsl,ls2088a-serdes1
> + - fsl,ls2088a-serdes2
> +
> + reg:
> + maxItems: 1
> +
> + big-endian: true
This isn't a required property, but should it be made required for the
specific compatibles that are big endian? Or are we not that lucky, and
devices can be either?
Cheers,
Conor.
> +
> + "#phy-cells":
> + const: 1
> +
> + "#address-cells":
> + const: 1
> +
> + "#size-cells":
> + const: 0
> +
> +patternProperties:
> + "^phy@[0-7]$":
> + type: object
> + description: SerDes lane (single RX/TX differential pair)
> +
> + properties:
> + reg:
> + minimum: 0
> + maximum: 7
> + description: Lane index as seen in register map
> +
> + "#phy-cells":
> + const: 0
> +
> + required:
> + - reg
> + - "#phy-cells"
> +
> + additionalProperties: false
> +
> +required:
> + - compatible
> + - reg
> + - "#phy-cells"
> + - "#address-cells"
> + - "#size-cells"
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - fsl,ls1028a-serdes
> + - fsl,ls1046a-serdes1
> + - fsl,ls1046a-serdes2
> + - fsl,ls1088a-serdes1
> + - fsl,ls1088a-serdes2
> + then:
> + patternProperties:
> + "^phy@[0-7]$":
> + properties:
> + reg:
> + minimum: 0
> + maximum: 3
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + serdes@1ea0000 {
> + compatible = "fsl,ls1028a-serdes";
> + reg = <0x0 0x1ea0000 0x0 0xffff>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + #phy-cells = <1>;
> +
> + phy@0 {
> + reg = <0>;
> + #phy-cells = <0>;
> + };
> +
> + phy@1 {
> + reg = <1>;
> + #phy-cells = <0>;
> + };
> +
> + phy@2 {
> + reg = <2>;
> + #phy-cells = <0>;
> + };
> +
> + phy@3 {
> + reg = <3>;
> + #phy-cells = <0>;
> + };
> + };
> + };
> --
> 2.34.1
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
From: Frank Li @ 2026-06-02 20:28 UTC (permalink / raw)
To: Felix Gu
Cc: Vinod Koul, Neil Armstrong, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Xu Yang, Jun Li, linux-phy, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260602-imx8mq-typec-v1-1-3debe9bc77d9@gmail.com>
On Tue, Jun 02, 2026 at 10:12:41PM +0800, Felix Gu wrote:
> If probe fails after imx95_usb_phy_get_tca() succeeds, the typec
> switch leaks because the only cleanup path was in .remove, which
> never runs on probe failure.
>
> Use devm_add_action_or_reset() so the switch is cleaned up on both
> probe failure and driver removal. The .remove callback and
> imx95_usb_phy_put_tca() are no longer needed.
>
> Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95")
> Signed-off-by: Felix Gu <ustc.gu@gmail.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 ++++++++-------------------
> 1 file changed, 8 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index b05d80e849a1..8af5a4f85698 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -173,8 +173,10 @@ static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device
> return sw;
> }
>
> -static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
> +static void tca_blk_put_typec_switch(void *data)
> {
> + struct typec_switch_dev *sw = data;
> +
> typec_switch_unregister(sw);
> }
>
> @@ -248,6 +250,7 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> struct device *dev = &pdev->dev;
> struct resource *res;
> struct tca_blk *tca;
> + int ret;
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> if (!res)
> @@ -266,17 +269,11 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> tca->orientation = TYPEC_ORIENTATION_NORMAL;
> tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
>
> - return tca;
> -}
> -
> -static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
> -{
> - struct tca_blk *tca = imx_phy->tca;
> -
> - if (!tca)
> - return;
> + ret = devm_add_action_or_reset(&pdev->dev, tca_blk_put_typec_switch, tca->sw);
> + if (ret)
> + return ERR_PTR(ret);
>
> - tca_blk_put_typec_switch(tca->sw);
> + return tca;
> }
>
> static u32 phy_tx_vref_tune_from_property(u32 percent)
> @@ -739,16 +736,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> return PTR_ERR_OR_ZERO(phy_provider);
> }
>
> -static void imx8mq_usb_phy_remove(struct platform_device *pdev)
> -{
> - struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
> -
> - imx95_usb_phy_put_tca(imx_phy);
> -}
> -
> static struct platform_driver imx8mq_usb_phy_driver = {
> .probe = imx8mq_usb_phy_probe,
> - .remove = imx8mq_usb_phy_remove,
> .driver = {
> .name = "imx8mq-usb-phy",
> .of_match_table = imx8mq_usb_phy_of_match,
>
> ---
> base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
> change-id: 20260602-imx8mq-typec-20a6f1d1900f
>
> Best regards,
> --
> Felix Gu <ustc.gu@gmail.com>
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Frank Li @ 2026-06-02 20:55 UTC (permalink / raw)
To: Bryan O'Donoghue
Cc: Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <20260523-x1e-csi2-phy-v8-1-a85668459521@linaro.org>
On Sat, May 23, 2026 at 03:48:47AM +0100, Bryan O'Donoghue wrote:
> Add a base schema initially compatible with x1e80100 to describe MIPI CSI2
> PHY devices.
>
> The hardware can support both CPHY, DPHY and a special split-mode DPHY.
>
> The schema here defines three ports:
>
> port@0:
> The first input port where a sensor is always required.
>
> port@1:
> A second optional input port which if present implies DPHY split-mode.
>
> port@2:
> A third always required output port which connects to the controller.
Most likely CSI controller binding to descript connect graph. PHY should
be simple and straigh forward to change digial signal to analog signal.
most system work like
phy {
...
}
csi2 {
phy=<&phy>;
port@0: {
}
...
}
Frank
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Bryan O'Donoghue @ 2026-06-02 21:00 UTC (permalink / raw)
To: Frank Li
Cc: Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Neil Armstrong,
Bryan O'Donoghue, Vladimir Zapolskiy, linux-arm-msm,
linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <ah9DMPcKUaTm324I@lizhi-Precision-Tower-5810>
On 02/06/2026 21:55, Frank Li wrote:
> phy {
> ...
> }
>
> csi2 {
> phy=<&phy>;
>
> port@0: {
> }
> ...
> }
Agreed.
However, we also want to support "split-mode" which is a special mode of
this PHY where two sensors can be connected to one CSIPHY.
After a lot of debate adding ports/endpoints to the CSIPHY itself has
been pretty much settled on.
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Vladimir Zapolskiy @ 2026-06-02 21:59 UTC (permalink / raw)
To: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: Bryan O'Donoghue, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <20260523-x1e-csi2-phy-v8-1-a85668459521@linaro.org>
On 5/23/26 05:48, Bryan O'Donoghue wrote:
> Add a base schema initially compatible with x1e80100 to describe MIPI CSI2
> PHY devices.
>
> The hardware can support both CPHY, DPHY and a special split-mode DPHY.
>
> The schema here defines three ports:
>
> port@0:
> The first input port where a sensor is always required.
>
> port@1:
> A second optional input port which if present implies DPHY split-mode.
>
> port@2:
> A third always required output port which connects to the controller.
>
This port numeration is imperfect, because port@0 and port@2 are required,
while middle port@1 is optional.
Like it was stated before a number of times, it seems natural to operate
with two ports, where input port may have two endpoints rather than 3 ports,
also that approach solves the problem of a hole in the port numeration.
> The CSIPHY devices have their own pinouts on the SoC as well as their own
> individual voltage rails.
>
> The need to model voltage rails on a per-PHY basis leads us to define
> CSIPHY devices as individual nodes.
>
> Two nice outcomes in terms of schema and DT arise from this change.
>
> 1. The ability to define on a per-PHY basis voltage rails.
> 2. The ability to require those voltage.
>
> We have had a complete bodge upstream for this where a single set of
> voltage rail for all CSIPHYs has been buried inside of CAMSS.
>
> Much like the I2C bus which is dedicated to Camera sensors - the CCI bus in
> CAMSS parlance, the CSIPHY devices should be individually modelled.
>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
> .../bindings/phy/qcom,x1e80100-csi2-phy.yaml | 209 +++++++++++++++++++++
> 1 file changed, 209 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
> new file mode 100644
> index 0000000000000..270375f949880
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
> @@ -0,0 +1,209 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/qcom,x1e80100-csi2-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm CSI2 PHY
> +
> +maintainers:
> + - Bryan O'Donoghue <bod@kernel.org>
> +
> +description:
> + Qualcomm MIPI CSI2 C-PHY/D-PHY combination PHY. Connects MIPI CSI2 sensors
> + to Qualcomm's Camera CSI Decoder. The PHY supports both C-PHY and D-PHY
> + modes.
> +
> +properties:
> + compatible:
> + const: qcom,x1e80100-csi2-phy
> +
> + reg:
> + maxItems: 1
> +
> + "#phy-cells":
> + const: 1
> + description:
> + The single cell specifies the PHY operating mode.
#phy-cells should be 0, because the PHY operating mode is well defined
by 'bus-type' property of an endpoint on the sensor side, the opposite
side of CAMSS/CSID as a CSIPHY "consumer" should not dictate the PHY type.
> +
> + clocks:
> + maxItems: 2
> +
> + clock-names:
> + items:
> + - const: core
> + - const: timer
> +
> + interrupts:
> + maxItems: 1
> +
> + operating-points-v2:
> + maxItems: 1
> +
> + power-domains:
> + items:
> + - description: MMCX voltage rail
> + - description: MXC or MXA voltage rail
Only "qcom,x1e80100-csi2-phy" device is supported so far, unlikely it's
the case that "MXC or MXA voltage rail" should be specified, it'd be
just one of two or both.
> +
> + power-domain-names:
> + items:
> + - const: mmcx
> + - const: mx
> +
> + vdda-0p9-supply:
> + description: Phandle to a 0.9V regulator supply to a PHY.
> +
> + vdda-1p2-supply:
> + description: Phandle to 1.2V regulator supply to a PHY.
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + description: Sensor input. Always present.
> + unevaluatedProperties: false
> +
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> + properties:
> + data-lanes:
> + minItems: 1
> + maxItems: 4
> + clock-lanes:
> + maxItems: 1
> + remote-endpoint: true
> + required:
> + - data-lanes
> + - remote-endpoint
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + description:
> + Second sensor input. When present, indicates DPHY split mode.
> + unevaluatedProperties: false
> +
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> + properties:
> + data-lanes:
> + maxItems: 1
> + clock-lanes:
> + maxItems: 1
> + remote-endpoint: true
> + required:
> + - data-lanes
> + - clock-lanes
> + - remote-endpoint
As it's stated above, it should be converted to a single port with two
endpoints, it'd be done in accordance to video-interfaces.yaml.
> +
> + port@2:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + description: Output to CAMSS controller.
> + unevaluatedProperties: false
> +
> + properties:
> + endpoint:
> + $ref: /schemas/graph.yaml#/$defs/endpoint-base
> + unevaluatedProperties: false
> + properties:
> + remote-endpoint: true
> + required:
> + - remote-endpoint
> +
> + required:
> + - port@0
> + - port@2
> +
> +required:
> + - compatible
> + - reg
> + - "#phy-cells"
> + - clocks
> + - clock-names
> + - interrupts
> + - operating-points-v2
> + - power-domains
> + - power-domain-names
> + - vdda-0p9-supply
> + - vdda-1p2-supply
> + - ports
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/clock/qcom,x1e80100-camcc.h>
> + #include <dt-bindings/clock/qcom,x1e80100-gcc.h>
> + #include <dt-bindings/power/qcom,rpmhpd.h>
> +
> + csiphy4: csiphy@ace4000 {
> + compatible = "qcom,x1e80100-csi2-phy";
> + reg = <0x0ace4000 0x2000>;
> + #phy-cells = <1>;
> +
> + clocks = <&camcc CAM_CC_CSIPHY0_CLK>,
> + <&camcc CAM_CC_CSI0PHYTIMER_CLK>;
> + clock-names = "core",
> + "timer";
> +
> + operating-points-v2 = <&csiphy_opp_table>;
> +
> + interrupts = <GIC_SPI 477 IRQ_TYPE_EDGE_RISING>;
> +
> + power-domains = <&rpmhpd RPMHPD_MMCX>,
> + <&rpmhpd RPMHPD_MX>;
> + power-domain-names = "mmcx",
> + "mx";
> +
> + vdda-0p9-supply = <&vreg_l2c_0p8>;
> + vdda-1p2-supply = <&vreg_l1c_1p2>;
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> + csiphy0_in_ep: endpoint {
> + data-lanes = <0 1>;
> + clock-lanes = <2>;
> + remote-endpoint = <&sensor_out>;
> + };
> + };
> +
> + port@2 {
> + reg = <2>;
> + csiphy0_out_ep: endpoint {
> + remote-endpoint = <&controller_in>;
> + };
> + };
> + };
> + };
> +
> + csiphy_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + opp-300000000 {
> + opp-hz = /bits/ 64 <300000000>;
> + required-opps = <&rpmhpd_opp_low_svs_d1>,
> + <&rpmhpd_opp_low_svs_d1>;
> + };
> +
> + opp-400000000 {
> + opp-hz = /bits/ 64 <400000000>;
> + required-opps = <&rpmhpd_opp_low_svs>,
> + <&rpmhpd_opp_low_svs_d1>;
> + };
> +
> + opp-480000000 {
> + opp-hz = /bits/ 64 <480000000>;
> + required-opps = <&rpmhpd_opp_low_svs>,
> + <&rpmhpd_opp_low_svs_d1>;
> + };
> + };
>
--
Best wishes,
Vladimir
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Vladimir Zapolskiy @ 2026-06-02 22:07 UTC (permalink / raw)
To: Bryan O'Donoghue, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: Bryan O'Donoghue, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <20260523-x1e-csi2-phy-v8-2-a85668459521@linaro.org>
On 5/23/26 05:48, Bryan O'Donoghue wrote:
> Add a new MIPI CSI2 driver in DPHY mode initially. The entire set of
> existing CAMSS CSI PHY init sequences are imported in order to save time
> and effort in later patches.
>
> The following devices are supported in this drop:
> "qcom,x1e80100-csi2-phy"
>
> In-line with other PHY drivers the process node is included in the name.
> Data-lane and clock lane positioning and polarity selection via newly
> amended struct phy_configure_opts_mipi_dphy{} is supported.
>
> The Qualcomm 3PH class of PHYs can do both DPHY and CPHY mode. For now only
> DPHY is supported.
>
> In porting some of the logic over from camss-csiphy*.c to here its also
> possible to rationalise some of the code.
>
> In particular use of regulator_bulk and clk_bulk as well as dropping the
> seemingly useless and unused interrupt handler.
>
> The PHY sequences and a lot of the logic that goes with them are well
> proven in CAMSS and mature so the main thing to watch out for here is how
> to get the right sequencing of regulators, clocks and register-writes.
>
> The register init sequence table is imported verbatim from the existing
> CAMSS csiphy driver. A follow-up series will rework the table to extract
> the repetitive per-lane pattern into a loop.
>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
<>
> +static int phy_qcom_mipi_csi2_parse_routing(struct mipi_csi2phy_device *csi2phy)
> +{
> + struct mipi_csi2phy_stream_cfg *stream_cfg = &csi2phy->stream_cfg;
> + u32 lane_polarities[CSI2_MAX_DATA_LANES + 1];
> + u32 data_lanes[CSI2_MAX_DATA_LANES];
> + struct device *dev = csi2phy->dev;
> + struct fwnode_handle *ep;
> + int num_polarities;
> + int num_data_lanes;
> + u32 clock_lane;
> + int i, ret;
> +
> + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 1, 0,
> + FWNODE_GRAPH_ENDPOINT_NEXT);
> + if (ep) {
> + fwnode_handle_put(ep);
> + dev_err(dev, "DPHY split mode is not supported\n");
> + return -EOPNOTSUPP;
> + }
> +
> + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
> + if (!ep) {
> + dev_err(dev, "Missing port@0\n");
> + return -ENODEV;
> + }
> +
> + num_data_lanes = fwnode_property_count_u32(ep, "data-lanes");
> + if (num_data_lanes < 1 || num_data_lanes > CSI2_MAX_DATA_LANES) {
> + ret = -EINVAL;
> + dev_err(dev, "Invalid data-lanes count: %d\n", num_data_lanes);
> + goto out_put;
> + }
> + stream_cfg->num_data_lanes = num_data_lanes;
> +
> + ret = fwnode_property_read_u32_array(ep, "data-lanes", data_lanes,
> + stream_cfg->num_data_lanes);
> + if (ret) {
> + dev_err(dev, "Failed to read data-lanes: %d\n", ret);
> + goto out_put;
> + }
> +
> + ret = fwnode_property_read_u32(ep, "clock-lanes", &clock_lane);
> + if (ret) {
> + clock_lane = CSI2_DEFAULT_CLK_LN;
> + dev_info(dev, "Using default clock-lane %d\n",
> + CSI2_DEFAULT_CLK_LN);
Why CSI2_DEFAULT_CLK_LN is set to 7, what does it mean and how is it used?
Since "7" is a meaningless number in the context, I believe it's practically
not used at all, and if so, 'clock-lanes' property should be just removed.
> + }
--
Best wishes,
Vladimir
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 2/2] phy: qcom-mipi-csi2: Add a CSI2 MIPI DPHY driver
From: Bryan O'Donoghue @ 2026-06-02 22:22 UTC (permalink / raw)
To: Vladimir Zapolskiy, Vinod Koul, Kishon Vijay Abraham I,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Neil Armstrong
Cc: Bryan O'Donoghue, linux-arm-msm, linux-phy, linux-media,
devicetree, linux-kernel
In-Reply-To: <54904b61-222d-4600-ad4c-c03a9952d337@linaro.org>
On 02/06/2026 23:07, Vladimir Zapolskiy wrote:
>> + ret = fwnode_property_read_u32(ep, "clock-lanes", &clock_lane);
>> + if (ret) {
>> + clock_lane = CSI2_DEFAULT_CLK_LN;
>> + dev_info(dev, "Using default clock-lane %d\n",
>> + CSI2_DEFAULT_CLK_LN);
>
> Why CSI2_DEFAULT_CLK_LN is set to 7, what does it mean and how is it used?
>
> Since "7" is a meaningless number in the context, I believe it's
> practically
> not used at all, and if so, 'clock-lanes' property should be just removed.
Documentation shows clock lane at lane 7.
Truthfully it makes no sense that the clock lane would genuinely be
locked to lane 7 but the documentation does seem to suggest it.
Yes in fact I agree. clock-lanes can be reintroduced if someone can show
hardware that supports/depends on it.
---
bod
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v8 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Bryan O'Donoghue @ 2026-06-02 22:51 UTC (permalink / raw)
To: Vladimir Zapolskiy, Bryan O'Donoghue, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong
Cc: linux-arm-msm, linux-phy, linux-media, devicetree, linux-kernel
In-Reply-To: <dda32577-04e0-4507-acaf-a5694f4f31b3@linaro.org>
On 02/06/2026 22:59, Vladimir Zapolskiy wrote:
> On 5/23/26 05:48, Bryan O'Donoghue wrote:
>> Add a base schema initially compatible with x1e80100 to describe MIPI CSI2
>> PHY devices.
>>
>> The hardware can support both CPHY, DPHY and a special split-mode DPHY.
>>
>> The schema here defines three ports:
>>
>> port@0:
>> The first input port where a sensor is always required.
>>
>> port@1:
>> A second optional input port which if present implies DPHY split-mode.
>>
>> port@2:
>> A third always required output port which connects to the controller.
>>
>
> This port numeration is imperfect, because port@0 and port@2 are required,
> while middle port@1 is optional.
>
> Like it was stated before a number of times, it seems natural to operate
> with two ports, where input port may have two endpoints rather than 3 ports,
> also that approach solves the problem of a hole in the port numeration.
Can you confirm this is what you are after ?
port@0 {
#address-cells = <1>;
#size-cells = <0>;
endpoint@0 { /* primary sensor */
reg = <0>;
data-lanes = <0 1 2 3>;
remote-endpoint = <&sensor0_out>;
};
endpoint@1 { /* split-mode second sensor, optional */
reg = <1>;
data-lanes = <0>;
remote-endpoint = <&sensor1_out>;
};
};
port@1 { /* output to CAMSS, was port@2 */
endpoint { remote-endpoint = <&controller_in>; };
};
This works for me BTW.
>> The CSIPHY devices have their own pinouts on the SoC as well as their own
>> individual voltage rails.
>>
>> The need to model voltage rails on a per-PHY basis leads us to define
>> CSIPHY devices as individual nodes.
>>
>> Two nice outcomes in terms of schema and DT arise from this change.
>>
>> 1. The ability to define on a per-PHY basis voltage rails.
>> 2. The ability to require those voltage.
>>
>> We have had a complete bodge upstream for this where a single set of
>> voltage rail for all CSIPHYs has been buried inside of CAMSS.
>>
>> Much like the I2C bus which is dedicated to Camera sensors - the CCI bus in
>> CAMSS parlance, the CSIPHY devices should be individually modelled.
>>
>> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
>> ---
>> .../bindings/phy/qcom,x1e80100-csi2-phy.yaml | 209 +++++++++++++++++++++
>> 1 file changed, 209 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
>> new file mode 100644
>> index 0000000000000..270375f949880
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml
>> @@ -0,0 +1,209 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/phy/qcom,x1e80100-csi2-phy.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Qualcomm CSI2 PHY
>> +
>> +maintainers:
>> + - Bryan O'Donoghue <bod@kernel.org>
>> +
>> +description:
>> + Qualcomm MIPI CSI2 C-PHY/D-PHY combination PHY. Connects MIPI CSI2 sensors
>> + to Qualcomm's Camera CSI Decoder. The PHY supports both C-PHY and D-PHY
>> + modes.
>> +
>> +properties:
>> + compatible:
>> + const: qcom,x1e80100-csi2-phy
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + "#phy-cells":
>> + const: 1
>> + description:
>> + The single cell specifies the PHY operating mode.
>
> #phy-cells should be 0, because the PHY operating mode is well defined
> by 'bus-type' property of an endpoint on the sensor side, the opposite
> side of CAMSS/CSID as a CSIPHY "consumer" should not dictate the PHY type.
Rob said consumer but, I'm also not very bothered about that. bus-type
is perfectly acceptable to me.
>> +
>> + clocks:
>> + maxItems: 2
>> +
>> + clock-names:
>> + items:
>> + - const: core
>> + - const: timer
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + operating-points-v2:
>> + maxItems: 1
>> +
>> + power-domains:
>> + items:
>> + - description: MMCX voltage rail
>> + - description: MXC or MXA voltage rail
>
> Only "qcom,x1e80100-csi2-phy" device is supported so far, unlikely it's
> the case that "MXC or MXA voltage rail" should be specified, it'd be
> just one of two or both.
Hmm. I'm not being clear here if this is your take, I will reword it to
make it clearer this generation of PHY _must_ have either
- MMCX and MXC
or
- MMCX and MXA
>> +
>> + power-domain-names:
>> + items:
>> + - const: mmcx
>> + - const: mx
>> +
>> + vdda-0p9-supply:
>> + description: Phandle to a 0.9V regulator supply to a PHY.
>> +
>> + vdda-1p2-supply:
>> + description: Phandle to 1.2V regulator supply to a PHY.
>> +
>> + ports:
>> + $ref: /schemas/graph.yaml#/properties/ports
>> +
>> + properties:
>> + port@0:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + description: Sensor input. Always present.
>> + unevaluatedProperties: false
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> + properties:
>> + data-lanes:
>> + minItems: 1
>> + maxItems: 4
>> + clock-lanes:
>> + maxItems: 1
>> + remote-endpoint: true
>> + required:
>> + - data-lanes
>> + - remote-endpoint
>> +
>> + port@1:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + description:
>> + Second sensor input. When present, indicates DPHY split mode.
>> + unevaluatedProperties: false
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> + properties:
>> + data-lanes:
>> + maxItems: 1
>> + clock-lanes:
>> + maxItems: 1
>> + remote-endpoint: true
>> + required:
>> + - data-lanes
>> + - clock-lanes
>> + - remote-endpoint
>
> As it's stated above, it should be converted to a single port with two
> endpoints, it'd be done in accordance to video-interfaces.yaml.
>
>> +
>> + port@2:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + description: Output to CAMSS controller.
>> + unevaluatedProperties: false
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/graph.yaml#/$defs/endpoint-base
>> + unevaluatedProperties: false
>> + properties:
>> + remote-endpoint: true
>> + required:
>> + - remote-endpoint
>> +
>> + required:
>> + - port@0
>> + - port@2
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - "#phy-cells"
>> + - clocks
>> + - clock-names
>> + - interrupts
>> + - operating-points-v2
>> + - power-domains
>> + - power-domain-names
>> + - vdda-0p9-supply
>> + - vdda-1p2-supply
>> + - ports
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/clock/qcom,x1e80100-camcc.h>
>> + #include <dt-bindings/clock/qcom,x1e80100-gcc.h>
>> + #include <dt-bindings/power/qcom,rpmhpd.h>
>> +
>> + csiphy4: csiphy@ace4000 {
>> + compatible = "qcom,x1e80100-csi2-phy";
>> + reg = <0x0ace4000 0x2000>;
>> + #phy-cells = <1>;
>> +
>> + clocks = <&camcc CAM_CC_CSIPHY0_CLK>,
>> + <&camcc CAM_CC_CSI0PHYTIMER_CLK>;
>> + clock-names = "core",
>> + "timer";
>> +
>> + operating-points-v2 = <&csiphy_opp_table>;
>> +
>> + interrupts = <GIC_SPI 477 IRQ_TYPE_EDGE_RISING>;
>> +
>> + power-domains = <&rpmhpd RPMHPD_MMCX>,
>> + <&rpmhpd RPMHPD_MX>;
>> + power-domain-names = "mmcx",
>> + "mx";
>> +
>> + vdda-0p9-supply = <&vreg_l2c_0p8>;
>> + vdda-1p2-supply = <&vreg_l1c_1p2>;
>> +
>> + ports {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + port@0 {
>> + reg = <0>;
>> + csiphy0_in_ep: endpoint {
>> + data-lanes = <0 1>;
>> + clock-lanes = <2>;
>> + remote-endpoint = <&sensor_out>;
>> + };
>> + };
>> +
>> + port@2 {
>> + reg = <2>;
>> + csiphy0_out_ep: endpoint {
>> + remote-endpoint = <&controller_in>;
>> + };
>> + };
>> + };
>> + };
>> +
>> + csiphy_opp_table: opp-table {
>> + compatible = "operating-points-v2";
>> +
>> + opp-300000000 {
>> + opp-hz = /bits/ 64 <300000000>;
>> + required-opps = <&rpmhpd_opp_low_svs_d1>,
>> + <&rpmhpd_opp_low_svs_d1>;
>> + };
>> +
>> + opp-400000000 {
>> + opp-hz = /bits/ 64 <400000000>;
>> + required-opps = <&rpmhpd_opp_low_svs>,
>> + <&rpmhpd_opp_low_svs_d1>;
>> + };
>> +
>> + opp-480000000 {
>> + opp-hz = /bits/ 64 <480000000>;
>> + required-opps = <&rpmhpd_opp_low_svs>,
>> + <&rpmhpd_opp_low_svs_d1>;
>> + };
>> + };
>>
>
> --
> Best wishes,
> Vladimir
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
From: Xu Yang @ 2026-06-03 3:09 UTC (permalink / raw)
To: Felix Gu
Cc: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Xu Yang, Jun Li,
linux-phy, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20260602-imx8mq-typec-v1-1-3debe9bc77d9@gmail.com>
On Tue, Jun 02, 2026 at 10:12:41PM +0800, Felix Gu wrote:
> If probe fails after imx95_usb_phy_get_tca() succeeds, the typec
> switch leaks because the only cleanup path was in .remove, which
> never runs on probe failure.
>
> Use devm_add_action_or_reset() so the switch is cleaned up on both
> probe failure and driver removal. The .remove callback and
> imx95_usb_phy_put_tca() are no longer needed.
>
> Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95")
> Signed-off-by: Felix Gu <ustc.gu@gmail.com>
> ---
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 ++++++++-------------------
> 1 file changed, 8 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index b05d80e849a1..8af5a4f85698 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -173,8 +173,10 @@ static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device
> return sw;
> }
>
> -static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
> +static void tca_blk_put_typec_switch(void *data)
> {
> + struct typec_switch_dev *sw = data;
> +
> typec_switch_unregister(sw);
> }
Nit: You can simply call typec_switch_unregister(data)
Reviewed-by: Xu Yang <xu.yang_2@nxp.com>
>
> @@ -248,6 +250,7 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> struct device *dev = &pdev->dev;
> struct resource *res;
> struct tca_blk *tca;
> + int ret;
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> if (!res)
> @@ -266,17 +269,11 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> tca->orientation = TYPEC_ORIENTATION_NORMAL;
> tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
>
> - return tca;
> -}
> -
> -static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
> -{
> - struct tca_blk *tca = imx_phy->tca;
> -
> - if (!tca)
> - return;
> + ret = devm_add_action_or_reset(&pdev->dev, tca_blk_put_typec_switch, tca->sw);
> + if (ret)
> + return ERR_PTR(ret);
>
> - tca_blk_put_typec_switch(tca->sw);
> + return tca;
> }
>
> static u32 phy_tx_vref_tune_from_property(u32 percent)
> @@ -739,16 +736,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
> return PTR_ERR_OR_ZERO(phy_provider);
> }
>
> -static void imx8mq_usb_phy_remove(struct platform_device *pdev)
> -{
> - struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
> -
> - imx95_usb_phy_put_tca(imx_phy);
> -}
> -
> static struct platform_driver imx8mq_usb_phy_driver = {
> .probe = imx8mq_usb_phy_probe,
> - .remove = imx8mq_usb_phy_remove,
> .driver = {
> .name = "imx8mq-usb-phy",
> .of_match_table = imx8mq_usb_phy_of_match,
>
> ---
> base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
> change-id: 20260602-imx8mq-typec-20a6f1d1900f
>
> Best regards,
> --
> Felix Gu <ustc.gu@gmail.com>
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v3 0/5] phy: fsl-imx8mq-usb: few improvements
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Felix Gu, stable,
Xu Yang
This patchset is a continuous of v2, it mainly resolves some concerns
reported by sashiko-bot.
Patch #1 fix Type-C switch resource leak if probe() fails.
Patch #3 add runtime PM support to avoid register access issue if the
USB controller enters into runtime suspended state, in this state
accessing USB PHY register may lack some resources. This will also
avoid regulator leak if power_on() fails.
Patch #4 add debug control register regmap
Patch #5 correct i.MX8MP USB runtime wakeup issue after introduce runtime
PM support.
Link to v2:
- https://lore.kernel.org/linux-phy/20260512101046.1498096-1-xu.yang_2@nxp.com/
- https://lore.kernel.org/linux-phy/20260512101212.1498223-1-xu.yang_2@nxp.com/
---
Felix Gu (1):
phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
Xu Yang (4):
phy: fsl-imx8mq-usb: set usb phy to be wakeup capable
phy: fsl-imx8mq-usb: add runtime PM support
phy: fsl-imx8mq-usb: add control register regmap
phy: fsl-imx8mq-usb: keep PHY power domain runtime always-on for i.MX8MP
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 125 ++++++++++++++++++++---------
1 file changed, 88 insertions(+), 37 deletions(-)
---
base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
change-id: 20260602-imx8mp-usb-phy-improvement-4272d308d862
Best regards,
--
Xu Yang <xu.yang_2@nxp.com>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v3 1/5] phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Felix Gu, stable,
Xu Yang
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com>
From: Felix Gu <ustc.gu@gmail.com>
If probe fails after imx95_usb_phy_get_tca() succeeds, the typec
switch leaks because the only cleanup path was in .remove, which
never runs on probe failure.
Use devm_add_action_or_reset() so the switch is cleaned up on both
probe failure and driver removal. The .remove callback and
imx95_usb_phy_put_tca() are no longer needed.
Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Xu Yang <xu.yang_2@nxp.com>
Signed-off-by: Felix Gu <ustc.gu@gmail.com>
---
Changes in v3:
- add R-b tag
- cc statble
- drop "sw = data" conversion
---
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 +++++++--------------------
1 file changed, 7 insertions(+), 20 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index b05d80e849a1..88b804b2c982 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -173,9 +173,9 @@ static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device
return sw;
}
-static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
+static void tca_blk_put_typec_switch(void *data)
{
- typec_switch_unregister(sw);
+ typec_switch_unregister(data);
}
static void tca_blk_orientation_set(struct tca_blk *tca,
@@ -248,6 +248,7 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
struct device *dev = &pdev->dev;
struct resource *res;
struct tca_blk *tca;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res)
@@ -266,17 +267,11 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
tca->orientation = TYPEC_ORIENTATION_NORMAL;
tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
- return tca;
-}
-
-static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
-{
- struct tca_blk *tca = imx_phy->tca;
-
- if (!tca)
- return;
+ ret = devm_add_action_or_reset(&pdev->dev, tca_blk_put_typec_switch, tca->sw);
+ if (ret)
+ return ERR_PTR(ret);
- tca_blk_put_typec_switch(tca->sw);
+ return tca;
}
static u32 phy_tx_vref_tune_from_property(u32 percent)
@@ -739,16 +734,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
-static void imx8mq_usb_phy_remove(struct platform_device *pdev)
-{
- struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
-
- imx95_usb_phy_put_tca(imx_phy);
-}
-
static struct platform_driver imx8mq_usb_phy_driver = {
.probe = imx8mq_usb_phy_probe,
- .remove = imx8mq_usb_phy_remove,
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v3 2/5] phy: fsl-imx8mq-usb: set usb phy to be wakeup capable
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Xu Yang
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com>
From: Xu Yang <xu.yang_2@nxp.com>
Set PHY wakeup capable because this PHY supports remote wakeup function.
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v3:
- no changes
Changes in v2:
- no changes
---
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 88b804b2c982..591ddf346061 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -728,6 +728,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
"failed to get tca\n");
imx8m_get_phy_tuning_data(imx_phy);
+ device_set_wakeup_capable(dev, true);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v3 3/5] phy: fsl-imx8mq-usb: add runtime PM support
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Xu Yang
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com>
From: Xu Yang <xu.yang_2@nxp.com>
Add runtime PM to ensure the PHY is properly powered and clocked during
register access, preventing potential system hangs.
It guards register access in the following scenarios:
- PHY operations: init() and power_on/off() callbacks are guarded by
phy core
- Type-C orientation switching when PHY/Controller are suspended which
needs explicitly care
- Future PHY control port register regmap debugfs access
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v3:
- new patch
---
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 60 ++++++++++++++++++++----------
1 file changed, 41 insertions(+), 19 deletions(-)
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 591ddf346061..b0092c34416e 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -9,6 +9,7 @@
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/typec_mux.h>
@@ -136,17 +137,13 @@ static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
{
struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
struct tca_blk *tca = imx_phy->tca;
- int ret;
if (tca->orientation == orientation)
return 0;
- ret = clk_prepare_enable(imx_phy->clk);
- if (ret)
- return ret;
+ guard(pm_runtime_active)(&imx_phy->phy->dev);
tca_blk_orientation_set(tca, orientation);
- clk_disable_unprepare(imx_phy->clk);
return 0;
}
@@ -620,16 +617,6 @@ static int imx8mq_phy_power_on(struct phy *phy)
if (ret)
return ret;
- ret = clk_prepare_enable(imx_phy->clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(imx_phy->alt_clk);
- if (ret) {
- clk_disable_unprepare(imx_phy->clk);
- return ret;
- }
-
/* Disable rx term override */
value = readl(imx_phy->base + PHY_CTRL6);
value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
@@ -648,8 +635,6 @@ static int imx8mq_phy_power_off(struct phy *phy)
value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
writel(value, imx_phy->base + PHY_CTRL6);
- clk_disable_unprepare(imx_phy->alt_clk);
- clk_disable_unprepare(imx_phy->clk);
regulator_disable(imx_phy->vbus);
return 0;
@@ -686,6 +671,7 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct imx8mq_usb_phy *imx_phy;
const struct phy_ops *phy_ops;
+ int ret;
imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
if (!imx_phy)
@@ -693,13 +679,13 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, imx_phy);
- imx_phy->clk = devm_clk_get(dev, "phy");
+ imx_phy->clk = devm_clk_get_enabled(dev, "phy");
if (IS_ERR(imx_phy->clk)) {
dev_err(dev, "failed to get imx8mq usb phy clock\n");
return PTR_ERR(imx_phy->clk);
}
- imx_phy->alt_clk = devm_clk_get_optional(dev, "alt");
+ imx_phy->alt_clk = devm_clk_get_optional_enabled(dev, "alt");
if (IS_ERR(imx_phy->alt_clk))
return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk),
"Failed to get alt clk\n");
@@ -708,6 +694,10 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (IS_ERR(imx_phy->base))
return PTR_ERR(imx_phy->base);
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+
phy_ops = of_device_get_match_data(dev);
if (!phy_ops)
return -EINVAL;
@@ -735,11 +725,43 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
+static int imx8mq_usb_phy_runtime_suspend(struct device *dev)
+{
+ struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(imx_phy->alt_clk);
+ clk_disable_unprepare(imx_phy->clk);
+
+ return 0;
+}
+
+static int imx8mq_usb_phy_runtime_resume(struct device *dev)
+{
+ struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(imx_phy->clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(imx_phy->alt_clk);
+ if (ret) {
+ clk_disable_unprepare(imx_phy->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx8mq_usb_phy_pm_ops, imx8mq_usb_phy_runtime_suspend,
+ imx8mq_usb_phy_runtime_resume, NULL);
+
static struct platform_driver imx8mq_usb_phy_driver = {
.probe = imx8mq_usb_phy_probe,
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
+ .pm = pm_ptr(&imx8mq_usb_phy_pm_ops),
.suppress_bind_attrs = true,
}
};
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v3 4/5] phy: fsl-imx8mq-usb: add control register regmap
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Xu Yang
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com>
From: Xu Yang <xu.yang_2@nxp.com>
The CR port is a simple 16-bit data/address parallel port that is
provided for on-chip access to the control registers inside the
USB 3.0 femtoPHY. Add control register regmap and export these
registers by debugfs to help PHY's diagnostic.
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v3:
- drop Frank's tag because it includes other changes
- new patch
---
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index b0092c34416e..cda88ea1f12d 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
-/* Copyright (c) 2017 NXP. */
+/* Copyright 2017-2026 NXP. */
#include <linux/bitfield.h>
#include <linux/clk.h>
@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
#include <linux/usb/typec_mux.h>
#define PHY_CTRL0 0x0
@@ -56,6 +57,8 @@
#define PHY_CTRL6_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
+#define PHY_CRCTL 0x30
+
#define PHY_TUNE_DEFAULT 0xffffffff
#define TCA_CLK_RST 0x00
@@ -119,6 +122,7 @@ struct imx8mq_usb_phy {
void __iomem *base;
struct regulator *vbus;
struct tca_blk *tca;
+ struct regmap *cr_regmap;
u32 pcs_tx_swing_full;
u32 pcs_tx_deemph_3p5db;
u32 tx_vref_tune;
@@ -665,6 +669,14 @@ static const struct of_device_id imx8mq_usb_phy_of_match[] = {
};
MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
+static const struct regmap_config imx_cr_regmap_config = {
+ .name = "cr",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x7,
+};
+
static int imx8mq_usb_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@@ -694,6 +706,13 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (IS_ERR(imx_phy->base))
return PTR_ERR(imx_phy->base);
+ imx_phy->cr_regmap = devm_regmap_init_mmio(dev, imx_phy->base + PHY_CRCTL,
+ &imx_cr_regmap_config);
+ if (IS_ERR(imx_phy->cr_regmap)) {
+ dev_warn(dev, "Fail to init debug register regmap\n");
+ imx_phy->cr_regmap = NULL;
+ }
+
ret = devm_pm_runtime_set_active_enabled(dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
@@ -729,6 +748,9 @@ static int imx8mq_usb_phy_runtime_suspend(struct device *dev)
{
struct imx8mq_usb_phy *imx_phy = dev_get_drvdata(dev);
+ if (imx_phy->cr_regmap)
+ regcache_cache_only(imx_phy->cr_regmap, true);
+
clk_disable_unprepare(imx_phy->alt_clk);
clk_disable_unprepare(imx_phy->clk);
@@ -750,6 +772,9 @@ static int imx8mq_usb_phy_runtime_resume(struct device *dev)
return ret;
}
+ if (imx_phy->cr_regmap)
+ regcache_cache_only(imx_phy->cr_regmap, false);
+
return 0;
}
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v3 5/5] phy: fsl-imx8mq-usb: keep PHY power domain runtime always-on for i.MX8MP
From: Xu Yang @ 2026-06-03 5:37 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Jun Li
Cc: linux-phy, imx, linux-arm-kernel, linux-kernel, Xu Yang
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com>
From: Xu Yang <xu.yang_2@nxp.com>
On i.MX8MP, the USB PHY has a dedicated power domain that was previously
never powered off at runtime. With the introduction of runtime PM support,
the power domain will be powered off if the device is runtime suspended,
which breaks USB wakeup functionality.
To preserve wakeup functionality, mark the PHY power domain as runtime
always-on for i.MX8MP platform. To limit the behavior to i.MX8MP, add a
new imx95_usb_phy_ops for i.MX95 and introduce usb_phy_is_imx8mp() helper
to identify i.MX8MP PHY instance.
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v3:
- new patch
---
drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index cda88ea1f12d..2c3c22c6c66d 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -9,6 +9,7 @@
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
@@ -658,13 +659,20 @@ static const struct phy_ops imx8mp_usb_phy_ops = {
.owner = THIS_MODULE,
};
+static const struct phy_ops imx95_usb_phy_ops = {
+ .init = imx8mp_usb_phy_init,
+ .power_on = imx8mq_phy_power_on,
+ .power_off = imx8mq_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
static const struct of_device_id imx8mq_usb_phy_of_match[] = {
{.compatible = "fsl,imx8mq-usb-phy",
.data = &imx8mq_usb_phy_ops,},
{.compatible = "fsl,imx8mp-usb-phy",
.data = &imx8mp_usb_phy_ops,},
{.compatible = "fsl,imx95-usb-phy",
- .data = &imx8mp_usb_phy_ops,},
+ .data = &imx95_usb_phy_ops,},
{ }
};
MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
@@ -677,6 +685,11 @@ static const struct regmap_config imx_cr_regmap_config = {
.max_register = 0x7,
};
+static bool usb_phy_is_imx8mp(const void *data)
+{
+ return data == &imx8mp_usb_phy_ops;
+}
+
static int imx8mq_usb_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@@ -721,6 +734,9 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (!phy_ops)
return -EINVAL;
+ if (usb_phy_is_imx8mp(phy_ops))
+ dev_pm_genpd_rpm_always_on(dev, true);
+
imx_phy->phy = devm_phy_create(dev, NULL, phy_ops);
if (IS_ERR(imx_phy->phy))
return PTR_ERR(imx_phy->phy);
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH] phy: fsl-imx8mq-usb: fix vbus regulator leak on error paths
From: Xu Yang @ 2026-06-03 5:39 UTC (permalink / raw)
To: Felix Gu
Cc: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Xu Yang, linux-phy, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260602-imx9mq-v1-1-e58b912923d2@gmail.com>
Hi Felix,
On Tue, Jun 02, 2026 at 09:14:33PM +0800, Felix Gu wrote:
> In imx8mq_phy_power_on(), if clk_prepare_enable() fails after
> regulator_enable() has succeeded, the vbus regulator is left
> enabled. The same issue exists for the alt_clk error path.
>
> Fix both by converting to the standard goto-based cleanup
> pattern, ensuring the regulator is disabled when any
> subsequent step fails.
I am fixing the bugs which are reported by sashiko-bot based on my previous
patch these days. And I already build a patchset to add runtime PM support
which will move all clock callbakcs to runtime operations. Therefore, this
patch is not needed anymore once runtime PM is ready.
Please refer to:
https://lore.kernel.org/linux-phy/20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com/T/#t
Thanks,
Xu Yang
>
> Fixes: 3b64ea4768e7 ("phy: fsl-imx8mq-usb: support alternate reference clock")
> Signed-off-by: Felix Gu <ustc.gu@gmail.com>
> ---
> drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index b05d80e849a1..e45e4f16057e 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -627,13 +627,11 @@ static int imx8mq_phy_power_on(struct phy *phy)
>
> ret = clk_prepare_enable(imx_phy->clk);
> if (ret)
> - return ret;
> + goto disable_vbus;
>
> ret = clk_prepare_enable(imx_phy->alt_clk);
> - if (ret) {
> - clk_disable_unprepare(imx_phy->clk);
> - return ret;
> - }
> + if (ret)
> + goto disable_clk;
>
> /* Disable rx term override */
> value = readl(imx_phy->base + PHY_CTRL6);
> @@ -641,6 +639,13 @@ static int imx8mq_phy_power_on(struct phy *phy)
> writel(value, imx_phy->base + PHY_CTRL6);
>
> return 0;
> +
> +disable_clk:
> + clk_disable_unprepare(imx_phy->clk);
> +disable_vbus:
> + regulator_disable(imx_phy->vbus);
> +
> + return ret;
> }
>
> static int imx8mq_phy_power_off(struct phy *phy)
>
> ---
> base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
> change-id: 20260602-imx9mq-30169239b590
>
> Best regards,
> --
> Felix Gu <ustc.gu@gmail.com>
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v3 1/5] phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
From: sashiko-bot @ 2026-06-03 5:43 UTC (permalink / raw)
To: Xu Yang; +Cc: imx, vkoul, olteanv, linux-phy, neil.armstrong, Frank.Li
In-Reply-To: <20260603-imx8mp-usb-phy-improvement-v3-1-7afb8f89abc6@nxp.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] A concurrent consumer can invoke the Type-C switch `.set` callback before `imx_phy->tca` is fully initialized, causing a NULL pointer dereference.
--
commit 0b20f824a9e9a9c613b1bcc66167f00382c9a5a1
Author: Felix Gu <ustc.gu@gmail.com>
phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
This patch fixes a typec switch leak on the probe error path by using
devm_add_action_or_reset. This allows cleaning up the switch on both
probe failure and driver removal, eliminating the need for a separate
remove callback.
> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
[ ... ]
> @@ -248,6 +248,7 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> struct device *dev = &pdev->dev;
> struct resource *res;
> struct tca_blk *tca;
> + int ret;
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> if (!res)
> @@ -266,17 +267,11 @@ static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
> tca->orientation = TYPEC_ORIENTATION_NORMAL;
> tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
[Severity: High]
This is a pre-existing issue, but is it possible for a concurrent consumer
to invoke the Type-C switch .set callback before imx_phy->tca is fully
initialized?
In tca_blk_get_typec_switch(), we call typec_switch_register() which makes
the switch visible to the system. Once registered, a consumer could
immediately resolve it and invoke its .set callback, which is
tca_blk_typec_switch_set().
If that happens, tca_blk_typec_switch_set() does:
tca_blk_typec_switch_set() {
struct tca_blk *tca = imx_phy->tca;
if (tca->orientation == orientation)
...
}
However, imx_phy->tca is assigned using the return value of this function
later in imx8mq_usb_phy_probe():
imx8mq_usb_phy_probe() {
...
imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy);
...
}
Could this race condition result in a NULL pointer dereference if the
callback fires before probe finishes assigning imx_phy->tca?
> - return tca;
> -}
> -
> -static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
> -{
> - struct tca_blk *tca = imx_phy->tca;
> -
> - if (!tca)
> - return;
> + ret = devm_add_action_or_reset(&pdev->dev, tca_blk_put_typec_switch, tca->sw);
> + if (ret)
> + return ERR_PTR(ret);
>
> - tca_blk_put_typec_switch(tca->sw);
> + return tca;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: fsl-imx8mq-usb: fix typec switch leak on probe error path
From: Xu Yang @ 2026-06-03 5:45 UTC (permalink / raw)
To: Felix Gu
Cc: Vinod Koul, Neil Armstrong, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Xu Yang, Jun Li,
linux-phy, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <ryzrcml3jo2lj657inrm6dlh2d3so7redxvjhhq3pbe435vq7n@khuctebwompe>
On Wed, Jun 03, 2026 at 11:09:32AM +0800, Xu Yang wrote:
> On Tue, Jun 02, 2026 at 10:12:41PM +0800, Felix Gu wrote:
> > If probe fails after imx95_usb_phy_get_tca() succeeds, the typec
> > switch leaks because the only cleanup path was in .remove, which
> > never runs on probe failure.
> >
> > Use devm_add_action_or_reset() so the switch is cleaned up on both
> > probe failure and driver removal. The .remove callback and
> > imx95_usb_phy_put_tca() are no longer needed.
> >
> > Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95")
> > Signed-off-by: Felix Gu <ustc.gu@gmail.com>
> > ---
> > drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 27 ++++++++-------------------
> > 1 file changed, 8 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > index b05d80e849a1..8af5a4f85698 100644
> > --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> > @@ -173,8 +173,10 @@ static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device
> > return sw;
> > }
> >
> > -static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
> > +static void tca_blk_put_typec_switch(void *data)
> > {
> > + struct typec_switch_dev *sw = data;
> > +
> > typec_switch_unregister(sw);
> > }
>
> Nit: You can simply call typec_switch_unregister(data)
>
> Reviewed-by: Xu Yang <xu.yang_2@nxp.com>
I have a similar patch in my patchset. I have added your patch to my patchset
because it has been reviewed and my other patches depend on this one. Otherwise,
rebase is needed for others.
https://lore.kernel.org/linux-phy/20260603-imx8mp-usb-phy-improvement-v3-0-7afb8f89abc6@nxp.com/T/#t
Thanks,
Xu Yang
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 0/2] phy: qcom: usb-hs: add qcom,vendor-init-seq for raw ULPI writes
From: Herman van Hazendonk @ 2026-06-03 5:48 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linux-arm-msm, Vinod Koul, Neil Armstrong,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Herman van Hazendonk
The qcom,usb-hs-phy driver already supports qcom,init-seq for
board-specific ULPI initialisation, but the address field in that
property is always offset by ULPI_EXT_VENDOR_SPECIFIC. That makes
it impossible to reach the standard ULPI vendor register range
(0x30-0x3f) where MSM8x60-class hardware keeps pre-emphasis, HS
driver slope, and CDR auto-reset bits.
PATCH 1/2 adds the DT binding: an optional "qcom,vendor-init-seq"
property carrying raw (addr, val) u8 pairs with no implicit offset.
PATCH 2/2 adds the driver support. The new sequence is applied AFTER
reset_control_reset() so the values survive the register restore the
reset performs. While refactoring the shared parse logic into a
single helper, two pre-existing bugs in the qcom,init-seq path are
also fixed: an odd byte count would previously silently drop the
trailing half-pair, and there was no upper bound on the
devm_kmalloc_array() allocation driven by the DT value.
Herman van Hazendonk (2):
dt-bindings: phy: qcom,usb-hs-phy: add qcom,vendor-init-seq
phy: qcom: usb-hs: honour qcom,vendor-init-seq raw ULPI writes
.../bindings/phy/qcom,usb-hs-phy.yaml | 14 +++
drivers/phy/qualcomm/phy-qcom-usb-hs.c | 109 +++++++++++++++---
2 files changed, 104 insertions(+), 19 deletions(-)
base-commit: 944125b4c454b58d2fe6e35f1087a932b2050dff
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 1/2] dt-bindings: phy: qcom,usb-hs-phy: add qcom,vendor-init-seq
From: Herman van Hazendonk @ 2026-06-03 5:48 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linux-arm-msm, Vinod Koul, Neil Armstrong,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Herman van Hazendonk
In-Reply-To: <20260603054809.565723-1-github.com@herrie.org>
Add an optional "qcom,vendor-init-seq" property carrying raw ULPI
(address, value) pairs that are written after PHY reset.
Unlike the existing "qcom,init-seq" property, the address field is
NOT offset by ULPI_EXT_VENDOR_SPECIFIC, so the new property can
reach the standard ULPI vendor register range (0x30-0x3f). MSM8x60-
class hardware needs this range to programme pre-emphasis, HS driver
slope and CDR auto-reset bits the legacy msm_otg driver used to set
via platform data.
The "qcom,init-seq" path is left unchanged.
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
---
.../devicetree/bindings/phy/qcom,usb-hs-phy.yaml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
index e03b516c698c..b9eca670419a 100644
--- a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
@@ -85,6 +85,20 @@ properties:
the address is offset from the ULPI_EXT_VENDOR_SPECIFIC address
- description: value
+ qcom,vendor-init-seq:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ description: >
+ Flat sequence of raw ULPI address/value byte pairs written after
+ the PHY reset. Each pair is two consecutive bytes:
+ [addr0, val0, addr1, val1, ...]. Total length must be even and
+ no more than 64 bytes (32 pairs). Unlike qcom,init-seq the
+ address field is not offset by ULPI_EXT_VENDOR_SPECIFIC, so this
+ property can reach the standard ULPI vendor range (0x30-0x3f) —
+ used on MSM8x60-class hardware to program pre-emphasis, HS
+ driver slope and CDR auto-reset bits the legacy msm_otg driver
+ used to set via platform data.
+ maxItems: 64
+
required:
- clocks
- clock-names
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 2/2] phy: qcom: usb-hs: honour qcom,vendor-init-seq raw ULPI writes
From: Herman van Hazendonk @ 2026-06-03 5:48 UTC (permalink / raw)
To: linux-phy
Cc: devicetree, linux-arm-msm, Vinod Koul, Neil Armstrong,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Herman van Hazendonk
In-Reply-To: <20260603054809.565723-1-github.com@herrie.org>
Add support for the optional qcom,vendor-init-seq DT property: a
list of u8 (addr, val) pairs written verbatim to raw ULPI register
addresses, rather than to ULPI_EXT_VENDOR_SPECIFIC + addr like the
existing qcom,init-seq sequence reaches. This lets boards reach the
standard vendor register range 0x30-0x3F where MSM8x60-era hardware
keeps pre-emphasis level / HS driver slope / CDR auto-reset, etc.
The new sequence is applied AFTER reset_control_reset() in
qcom_usb_hs_phy_power_on() so the values survive the register
restore the reset performs. The pre-existing qcom,init-seq is left
applied BEFORE the reset to preserve current behaviour for the
APQ8064/MSM8916 boards that already depend on it; an earlier review flagged
this ordering as a likely pre-existing bug, but blindly reordering
established behaviour for those boards is out of scope for this
patch and would risk regressing them.
While at it, harden the parse logic shared between qcom,init-seq
and qcom,vendor-init-seq:
- Reject an odd byte count up-front rather than silently dropping
the trailing byte and producing a half-pair the rest of the
driver cannot describe.
- Reject more than 32 bytes (the binding's maxItems) rather than
making an unbounded devm_kmalloc_array() allocation driven by
an untrusted-shaped DT property.
Factor the duplicated parse-and-allocate sequence into
qcom_usb_hs_phy_parse_init_seq() so both properties get the same
validation. The validation also fixes the pre-existing same bugs in
the qcom,init-seq parse path uniformly with the new property.
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
---
drivers/phy/qualcomm/phy-qcom-usb-hs.c | 109 ++++++++++++++++++++-----
1 file changed, 90 insertions(+), 19 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
index 98a18987f1be..89fbe8f8d001 100644
--- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c
+++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
@@ -35,6 +35,13 @@ struct qcom_usb_hs_phy {
struct regulator *v3p3;
struct reset_control *reset;
struct ulpi_seq *init_seq;
+ /*
+ * Optional sequence of writes targeting raw ULPI addresses (no
+ * ULPI_EXT_VENDOR_SPECIFIC base added). Populated from the
+ * "qcom,vendor-init-seq" DT property. Applied after PHY reset
+ * so the values survive the reset that follows init_seq writes.
+ */
+ struct ulpi_seq *vendor_init_seq;
struct extcon_dev *vbus_edev;
struct notifier_block vbus_notify;
};
@@ -154,6 +161,19 @@ static int qcom_usb_hs_phy_power_on(struct phy *phy)
goto err_ulpi;
}
+ /*
+ * Apply board-specific raw-address ULPI writes after the PHY reset
+ * so they survive register restore. Used to reach the standard
+ * vendor range 0x30-0x3F which qcom,init-seq (above) cannot —
+ * pre-emphasis level / HS driver slope / CDR auto-reset etc. live
+ * there on MSM8660-class hardware.
+ */
+ for (seq = uphy->vendor_init_seq; seq->addr; seq++) {
+ ret = ulpi_write(ulpi, seq->addr, seq->val);
+ if (ret)
+ goto err_ulpi;
+ }
+
if (uphy->vbus_edev) {
state = extcon_get_state(uphy->vbus_edev, EXTCON_USB);
/* setup initial state */
@@ -199,6 +219,59 @@ static const struct phy_ops qcom_usb_hs_phy_ops = {
.owner = THIS_MODULE,
};
+/*
+ * The binding caps both qcom,init-seq and qcom,vendor-init-seq at
+ * maxItems: 32 (addr, val) pairs, i.e. 64 bytes total. Enforce that
+ * limit here so a malformed DT cannot drive an unbounded
+ * devm_kmalloc_array() and so the misconfiguration is visible at
+ * probe time instead of silently truncated.
+ */
+#define QCOM_USB_HS_PHY_INIT_SEQ_MAX_PAIRS 32
+#define QCOM_USB_HS_PHY_INIT_SEQ_MAX_BYTES \
+ (QCOM_USB_HS_PHY_INIT_SEQ_MAX_PAIRS * 2)
+
+static int qcom_usb_hs_phy_parse_init_seq(struct ulpi *ulpi,
+ const char *propname,
+ struct ulpi_seq **out)
+{
+ struct ulpi_seq *seq;
+ int size;
+
+ size = of_property_count_u8_elems(ulpi->dev.of_node, propname);
+ if (size < 0)
+ size = 0;
+ if (size > QCOM_USB_HS_PHY_INIT_SEQ_MAX_BYTES) {
+ dev_err(&ulpi->dev,
+ "%s: %d bytes exceeds %d-byte maximum\n",
+ propname, size, QCOM_USB_HS_PHY_INIT_SEQ_MAX_BYTES);
+ return -EINVAL;
+ }
+ if (size % 2) {
+ dev_err(&ulpi->dev,
+ "%s: %d bytes is not a whole number of (addr, val) pairs\n",
+ propname, size);
+ return -EINVAL;
+ }
+
+ seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1, sizeof(*seq),
+ GFP_KERNEL);
+ if (!seq)
+ return -ENOMEM;
+
+ if (size) {
+ int ret = of_property_read_u8_array(ulpi->dev.of_node,
+ propname, (u8 *)seq, size);
+ if (ret)
+ return ret;
+ }
+ /* NUL-terminate so the power_on loop's seq->addr-as-sentinel works. */
+ seq[size / 2].addr = 0;
+ seq[size / 2].val = 0;
+
+ *out = seq;
+ return 0;
+}
+
static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
{
struct qcom_usb_hs_phy *uphy;
@@ -206,7 +279,6 @@ static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
struct clk *clk;
struct regulator *reg;
struct reset_control *reset;
- int size;
int ret;
uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
@@ -215,19 +287,20 @@ static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
ulpi_set_drvdata(ulpi, uphy);
uphy->ulpi = ulpi;
- size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq");
- if (size < 0)
- size = 0;
- uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1,
- sizeof(*uphy->init_seq), GFP_KERNEL);
- if (!uphy->init_seq)
- return -ENOMEM;
- ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq",
- (u8 *)uphy->init_seq, size);
- if (ret && size)
+ ret = qcom_usb_hs_phy_parse_init_seq(ulpi, "qcom,init-seq",
+ &uphy->init_seq);
+ if (ret)
+ return ret;
+ /*
+ * Optional raw-address vendor init sequence — same encoding as
+ * qcom,init-seq (u8 addr/val pairs) but each pair is written to
+ * the raw ULPI address rather than to ULPI_EXT_VENDOR_SPECIFIC +
+ * addr. Lets boards reach the standard vendor range 0x30-0x3F.
+ */
+ ret = qcom_usb_hs_phy_parse_init_seq(ulpi, "qcom,vendor-init-seq",
+ &uphy->vendor_init_seq);
+ if (ret)
return ret;
- /* NUL terminate */
- uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0;
uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref");
if (IS_ERR(clk))
@@ -245,12 +318,10 @@ static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
if (IS_ERR(reg))
return PTR_ERR(reg);
- uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por");
- if (IS_ERR(reset)) {
- if (PTR_ERR(reset) == -EPROBE_DEFER)
- return PTR_ERR(reset);
- uphy->reset = NULL;
- }
+ uphy->reset = reset = devm_reset_control_get_optional_exclusive(&ulpi->dev, "por");
+ if (IS_ERR(reset))
+ return dev_err_probe(&ulpi->dev, PTR_ERR(reset),
+ "failed to get reset control\n");
uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
&qcom_usb_hs_phy_ops);
--
2.43.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH 1/2] dt-bindings: phy: qcom,usb-hs-phy: add qcom,vendor-init-seq
From: sashiko-bot @ 2026-06-03 5:55 UTC (permalink / raw)
To: Herman van Hazendonk
Cc: robh, conor+dt, devicetree, olteanv, linux-phy, vkoul,
neil.armstrong
In-Reply-To: <20260603054809.565723-2-github.com@herrie.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The `qcom,vendor-init-seq` property uses a flat `uint8-array` type instead of `uint8-matrix`, preventing dt-schema from enforcing its required address-value pair structure.
--
commit c31501f8d171d100ea82c554966b30fc82a8bc2c
Author: Herman van Hazendonk <github.com@herrie.org>
dt-bindings: phy: qcom,usb-hs-phy: add qcom,vendor-init-seq
This commit introduces the qcom,vendor-init-seq property to the Qualcomm
USB HS PHY binding. It allows passing raw ULPI (address, value) pairs to
be written after PHY reset, targeting the standard ULPI vendor register
range for MSM8x60-class hardware configuration.
> diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
> index e03b516c698cc..b9eca670419a8 100644
> --- a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
> @@ -85,6 +85,20 @@ properties:
> the address is offset from the ULPI_EXT_VENDOR_SPECIFIC address
> - description: value
>
> + qcom,vendor-init-seq:
> + $ref: /schemas/types.yaml#/definitions/uint8-array
[Severity: Low]
Since the sequence consists of (address, value) pairs, should this use
/schemas/types.yaml#/definitions/uint8-matrix instead of uint8-array?
Using a uint8-matrix with an inner items list would allow the dt-schema
validation tool to statically catch malformed properties that do not have
an even number of bytes. This would structurally enforce the two-byte tuple
layout before runtime, similar to the existing qcom,init-seq property.
> + description: >
> + Flat sequence of raw ULPI address/value byte pairs written after
> + the PHY reset. Each pair is two consecutive bytes:
> + [addr0, val0, addr1, val1, ...]. Total length must be even and
> + no more than 64 bytes (32 pairs). Unlike qcom,init-seq the
> + address field is not offset by ULPI_EXT_VENDOR_SPECIFIC, so this
> + property can reach the standard ULPI vendor range (0x30-0x3f) —
> + used on MSM8x60-class hardware to program pre-emphasis, HS
> + driver slope and CDR auto-reset bits the legacy msm_otg driver
> + used to set via platform data.
> + maxItems: 64
> +
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603054809.565723-1-github.com@herrie.org?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 2/2] phy: qcom: usb-hs: honour qcom,vendor-init-seq raw ULPI writes
From: sashiko-bot @ 2026-06-03 6:01 UTC (permalink / raw)
To: Herman van Hazendonk
Cc: devicetree, robh, vkoul, neil.armstrong, linux-phy, olteanv,
conor+dt
In-Reply-To: <20260603054809.565723-3-github.com@herrie.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Using `seq->addr == 0` as a loop terminator prevents writing to offset 0 in `qcom,init-seq`.
--
commit 23768611bb7332cb583754c2260443d91ea51fb4
Author: Herman van Hazendonk <github.com@herrie.org>
phy: qcom: usb-hs: honour qcom,vendor-init-seq raw ULPI writes
This patch adds support for the optional qcom,vendor-init-seq DT property
to write directly to raw ULPI register addresses. It also hardens the parse
logic shared between qcom,init-seq and qcom,vendor-init-seq by factoring it
out into qcom_usb_hs_phy_parse_init_seq().
> diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
> index 98a18987f1bec..89fbe8f8d0015 100644
> --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c
> +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c
[ ... ]
> @@ -199,6 +219,59 @@ static const struct phy_ops qcom_usb_hs_phy_ops = {
[ ... ]
> +static int qcom_usb_hs_phy_parse_init_seq(struct ulpi *ulpi,
> + const char *propname,
> + struct ulpi_seq **out)
> +{
[ ... ]
> + if (size) {
> + int ret = of_property_read_u8_array(ulpi->dev.of_node,
> + propname, (u8 *)seq, size);
> + if (ret)
> + return ret;
> + }
> + /* NUL-terminate so the power_on loop's seq->addr-as-sentinel works. */
> + seq[size / 2].addr = 0;
[Severity: High]
This is a pre-existing issue, but does using seq->addr == 0 as a sentinel
prevent writing to offset 0 in qcom,init-seq?
In qcom_usb_hs_phy_power_on(), the initialization loop terminates when
seq->addr is 0:
for (seq = uphy->init_seq; seq->addr; seq++) {
ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr,
seq->val);
Since seq->addr represents an offset added to ULPI_EXT_VENDOR_SPECIFIC
for qcom,init-seq, an offset of 0 is valid and maps to the first vendor
specific register. If a device tree specifies a write to offset 0, won't
the loop prematurely terminate and silently truncate the remainder of the
initialization sequence?
> + seq[size / 2].val = 0;
> +
> + *out = seq;
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603054809.565723-1-github.com@herrie.org?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox