Linux-PHY Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH phy-next 1/2] dt-bindings: phy: add PHY bindings for the TI DS125DF111 Retimer PHY
From: Ioana Ciornei @ 2026-05-13 18:51 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
  Cc: devicetree, linux-kernel
In-Reply-To: <20260513185103.1371809-1-ioana.ciornei@nxp.com>

Add device tree binding for the TI DS125DF111 Retimer PHY.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 .../bindings/phy/ti,ds125df111.yaml           | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/ti,ds125df111.yaml

diff --git a/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
new file mode 100644
index 000000000000..47e9ba2a8990
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/ti,ds125df111.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI DS125DF111 Retimer PHY
+
+description:
+  This binding describes the TI DS125DF111 multi-protocol Retimer PHY.
+
+maintainers:
+  - Ioana Ciornei <ioana.ciornei@nxp.com>
+
+properties:
+  compatible:
+    const: ti,ds125df111
+
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 1
+    description: |
+      The phandle's argument in the PHY specifier selects one of the two
+      channels of the retimer
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      ti_retimer: retimer@18 {
+        compatible = "ti,ds125df111";
+        reg = <0x18>;
+        #phy-cells = <1>;
+      };
+    };
-- 
2.25.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH phy-next 2/2] phy: ti: add PHY driver for TI DS125DF111 Dual-Channel Retimer
From: Ioana Ciornei @ 2026-05-13 18:51 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
  Cc: devicetree, linux-kernel
In-Reply-To: <20260513185103.1371809-1-ioana.ciornei@nxp.com>

Add a generic PHY driver for the TI DS125DF111 Multi-Protocol
Dual-Channel Retimer. The driver currently supports only 10G and 1G link
speeds but it can easily extended to also cover other usecases.

Since the available datasheet (https://www.ti.com/lit/gpn/DS125DF111)
does not name the registers, the name for the macros were determined by
their usage pattern.

A PHY device is created for each of the two channels present on the
retimer. This allows for independent configuration of the two channels.
This capability is especially important on retimers which have more than
2 channels that can be, depending on the board design, connected in
multiple different ways to the SerDes lanes.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/phy/ti/Kconfig          |  10 ++
 drivers/phy/ti/Makefile         |   1 +
 drivers/phy/ti/phy-ds125df111.c | 245 ++++++++++++++++++++++++++++++++
 3 files changed, 256 insertions(+)
 create mode 100644 drivers/phy/ti/phy-ds125df111.c

diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig
index b40f28019131..475e80fcd52d 100644
--- a/drivers/phy/ti/Kconfig
+++ b/drivers/phy/ti/Kconfig
@@ -111,3 +111,13 @@ config PHY_TI_GMII_SEL
 	help
 	  This driver supports configuring of the TI CPSW Port mode depending on
 	  the Ethernet PHY connected to the CPSW Port.
+
+config PHY_TI_DS125DF111
+	tristate "DS125DF111 2-Channel Retimer Driver"
+	depends on OF && I2C
+	select GENERIC_PHY
+	help
+	  Enable this to add support for configuration and runtime management
+	  of the TI DS125DF111 Multi-Protocol 2-Channel Retimer.
+	  The retimer is modeled as a Generic PHY and supports both 10G and 1G
+	  link speeds.
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index dcba2571c9bd..e68445ddd848 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
 obj-$(CONFIG_PHY_AM654_SERDES)		+= phy-am654-serdes.o
 obj-$(CONFIG_PHY_TI_GMII_SEL)		+= phy-gmii-sel.o
 obj-$(CONFIG_PHY_J721E_WIZ)		+= phy-j721e-wiz.o
+obj-$(CONFIG_PHY_TI_DS125DF111)		+= phy-ds125df111.o
diff --git a/drivers/phy/ti/phy-ds125df111.c b/drivers/phy/ti/phy-ds125df111.c
new file mode 100644
index 000000000000..8ac10c603bf7
--- /dev/null
+++ b/drivers/phy/ti/phy-ds125df111.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2026 NXP */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+
+#define DS125DF111_NUM_CH			2
+#define DS125DF111_NUM_VCO_GROUP_REG		5
+
+#define DS125DF111_CH_SELECT			0xff
+#define DS125DF111_CH_SELECT_TARGET_MASK	GENMASK(3, 0)
+#define DS125DF111_CH_SELECT_EN			BIT(2)
+
+#define DS125DF111_CH_CTRL			0x00
+#define DS125DF111_CH_CTRL_RESET		BIT(2) /* self clearing */
+
+#define DS125DF111_VCO_GROUP_BASE		0x60
+
+#define DS125DF111_RATIOS			0x2F
+#define DS125DF111_RATIOS_RATE_MASK		GENMASK(7, 6)
+#define DS125DF111_RATIOS_SUBRATE_MASK		GENMASK(5, 4)
+
+struct ds125df111_ch {
+	struct phy *phy;
+	struct ds125df111_priv *priv;
+	int idx;
+};
+
+struct ds125df111_priv {
+	struct ds125df111_ch ch[DS125DF111_NUM_CH];
+	struct i2c_client *client;
+	struct mutex mutex; /* protects access to shared registers */
+};
+
+enum ds125df111_mode {
+	FREQ_1G,
+	FREQ_10G,
+};
+
+static const struct ds125df111_config {
+	u8 vco_group[DS125DF111_NUM_VCO_GROUP_REG];
+	u8 rate;
+	u8 subrate;
+} ds125df111_cfg[] = {
+	[FREQ_1G] = {
+		/* VCO group #0 = 10GHz, VCO group #1 = 10GHz */
+		.vco_group = {0x00, 0xB2, 0x00, 0xB2, 0xCC},
+		/* By using the following combination of rate and subrate we
+		 * select divide ratios of 1, 2, 4, 8 on both groups
+		 */
+		.rate = 0x1,
+		.subrate = 0x2,
+	},
+
+	[FREQ_10G] = {
+		/* VCO group #0 = 10.3125GHz, VCO group #1 = 10.3125GHz */
+		.vco_group = {0x90, 0xB3, 0x90, 0xB3, 0xCD},
+		/* By using the following combination of rate and subrate we
+		 * select divide ratios of 1 on both groups
+		 */
+		.rate = 0x1,
+		.subrate = 0x3,
+	},
+};
+
+static int ds125df111_configure(struct phy *phy,
+				const struct ds125df111_config *cfg)
+{
+	struct ds125df111_ch *ch = phy_get_drvdata(phy);
+	struct ds125df111_priv *priv = ch->priv;
+	struct i2c_client *i2c = priv->client;
+	struct device *dev = &phy->dev;
+	u8 val;
+	int err, i;
+
+	mutex_lock(&priv->mutex);
+
+	/* Make sure that any subsequent read/write operation will be directed
+	 * only to the registers of the selected channel
+	 */
+	err = i2c_smbus_read_byte_data(i2c, DS125DF111_CH_SELECT);
+	if (err < 0) {
+		dev_err(dev, "Unable to select channel\n");
+		goto out;
+	}
+	val = (u8)err;
+	val &= ~DS125DF111_CH_SELECT_TARGET_MASK;
+	val |= DS125DF111_CH_SELECT_EN | ch->idx;
+	err = i2c_smbus_write_byte_data(i2c, DS125DF111_CH_SELECT, val);
+	if (err < 0) {
+		dev_err(dev, "Unable to select channel\n");
+		goto out;
+	}
+
+	/* Reset Channel Registers */
+	err = i2c_smbus_read_byte_data(i2c, DS125DF111_CH_CTRL);
+	if (err < 0) {
+		dev_err(dev, "Error resetting channel configuration\n");
+		goto out;
+	}
+	val = (u8)err;
+	val |= DS125DF111_CH_CTRL_RESET;
+	err = i2c_smbus_write_byte_data(i2c, DS125DF111_CH_CTRL, val);
+	if (err < 0) {
+		dev_err(dev, "Error resetting channel configuration\n");
+		goto out;
+	}
+
+	/* Program the VCO group frequencies */
+	for (i = 0; i < DS125DF111_NUM_VCO_GROUP_REG; i++) {
+		err = i2c_smbus_write_byte_data(i2c,
+						DS125DF111_VCO_GROUP_BASE + i,
+						cfg->vco_group[i]);
+		if (err < 0) {
+			dev_err(dev, "Error programming VCO group frequencies\n");
+			goto out;
+		}
+	}
+
+	/* Set the Divide Ratios for the VCO Groups*/
+	err = i2c_smbus_read_byte_data(i2c, DS125DF111_RATIOS);
+	if (err < 0) {
+		dev_err(dev, "Error programming the divide ratios\n");
+		goto out;
+	}
+	val = (u8)err;
+	val &= ~(DS125DF111_RATIOS_RATE_MASK | DS125DF111_RATIOS_SUBRATE_MASK);
+	val |= FIELD_PREP(DS125DF111_RATIOS_RATE_MASK, cfg->rate) |
+		FIELD_PREP(DS125DF111_RATIOS_SUBRATE_MASK, cfg->subrate);
+	err = i2c_smbus_write_byte_data(i2c, DS125DF111_RATIOS, val);
+	if (err < 0) {
+		dev_err(dev, "Error programming the divide ratios\n");
+		goto out;
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+
+out:
+	mutex_unlock(&priv->mutex);
+
+	return err;
+}
+
+static int ds125df111_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+	const struct ds125df111_config *cfg;
+
+	if (mode != PHY_MODE_ETHERNET)
+		return -EOPNOTSUPP;
+
+	switch (submode) {
+	case PHY_INTERFACE_MODE_10GBASER:
+		cfg = &ds125df111_cfg[FREQ_10G];
+		break;
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_SGMII:
+		cfg = &ds125df111_cfg[FREQ_1G];
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return ds125df111_configure(phy, cfg);
+}
+
+static const struct phy_ops ds125df111_ops = {
+	.set_mode	= ds125df111_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *ds125df111_xlate(struct device *dev,
+				    const struct of_phandle_args *args)
+{
+	struct ds125df111_priv *priv = dev_get_drvdata(dev);
+	u32 idx = args->args[0];
+
+	if (idx >= DS125DF111_NUM_CH) {
+		dev_err(dev, "Maximum number of channels is %d\n",
+			DS125DF111_NUM_CH);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return priv->ch[idx].phy;
+}
+
+static int ds125df111_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct phy_provider *provider;
+	struct ds125df111_priv *priv;
+	int i, err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->client = client;
+	err = devm_mutex_init(dev, &priv->mutex);
+	if (err)
+		return err;
+
+	i2c_set_clientdata(client, priv);
+
+	for (i = 0; i < DS125DF111_NUM_CH; i++) {
+		struct ds125df111_ch *ch = &priv->ch[i];
+		struct phy *phy;
+
+		phy = devm_phy_create(dev, NULL, &ds125df111_ops);
+		if (IS_ERR(phy))
+			return PTR_ERR(phy);
+
+		ch->idx = i;
+		ch->priv = priv;
+		ch->phy = phy;
+
+		phy_set_drvdata(phy, ch);
+	}
+
+	provider = devm_of_phy_provider_register(dev, ds125df111_xlate);
+
+	return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id ds125df111_dt_ids[] = {
+	{ .compatible = "ti,ds125df111", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ds125df111_dt_ids);
+
+static struct i2c_driver ds125df111_driver = {
+	.driver = {
+		.name = "ds125df111",
+		.of_match_table = ds125df111_dt_ids,
+	},
+	.probe = ds125df111_probe,
+};
+module_i2c_driver(ds125df111_driver);
+
+MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
+MODULE_DESCRIPTION("TI DS125DF111 Retimer driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* Re: [PATCH v2 2/4] dt-bindings: phy: qcom,msm8998-qmp-usb3-phy: Add support for Shikra
From: Krzysztof Kozlowski @ 2026-05-13 18:56 UTC (permalink / raw)
  To: Krishna Kurapati
  Cc: Neil Armstrong, Vinod Koul, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Xiangxu Yin,
	Johan Hovold, Loic Poulain, Kathiravan Thirumoorthy,
	Dmitry Baryshkov, linux-arm-msm, linux-phy, devicetree,
	linux-kernel
In-Reply-To: <d52c5039-9431-44ed-9f3b-bb00d03ae176@oss.qualcomm.com>

On 07/05/2026 13:37, Krishna Kurapati wrote:
> 
> 
> On 5/5/2026 7:30 PM, Krzysztof Kozlowski wrote:
>> On 05/05/2026 15:57, Krishna Kurapati wrote:
>>>
>>>
>>> On 5/5/2026 6:59 PM, Krzysztof Kozlowski wrote:
>>>> On 05/05/2026 15:27, Krishna Kurapati wrote:
>>>>>
>>>>>
>>>>> On 5/5/2026 4:22 PM, Krzysztof Kozlowski wrote:
>>>>>> On 05/05/2026 12:49, Krzysztof Kozlowski wrote:
>>>>>>> On Mon, May 04, 2026 at 10:36:57PM +0530, Krishna Kurapati wrote:
>>>>>>>> Declare the USB-C QMP PHY present on the Qualcomm Shikra platform.
>>>>>>>>
>>>>>>>> Signed-off-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
>>>>>>>> ---
>>>>>>>>     .../devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml      | 2 ++
>>>>>>>>     1 file changed, 2 insertions(+)
>>>>>>>
>>>>>>> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>>>>>
>>>>>> ... and then I looked at the driver. So un-reviewed. Devices are clearly
>>>>>> compatible. If not, explain what is not compatible.
>>>>>>
>>>>> Talos uses GCC_USB3_PRIM_PHY_AUX_CLK.
>>>>>
>>>>> In Shikra, we are using GCC_USB3_PRIM_PHY_COM_AUX_CLK. We don't have
>>>>> GCC_USB3_PRIM_PHY_AUX_CLK.
>>>>>
>>>>> Hence, I didn't use a fallback compatible.
>>>>
>>>> This still explains nothing. How different clock makes interface for SW
>>>> incompatible exactly?
>>>>
>>> So I went by the naming. AUX vs COM_AUX.
>>
>> The naming does not matter. If the clock is called
>> "no_one_expects_spanish_inquisition", does that make software
>> incompatible? Why would the name itself matter?
>>
>>>
>>> Can I use a fallback compatible and in DT vote for "COM_AUX" clock with
>>> clock-names mentioning "aux" ?
>>
>> I don't know, I asked what is different in software interface.
>>
> 
> Hi Krzysztof,
> 
>   I checked with the hw team here and found out two things.
> 
>   1. Shikra is a spinoff of Agatti and its sw interface (clocks used and 
> regulators used) is the same as agatti.
> 
>   2. I thought we could use qcm2290 as a fallback since the phy register 
> init sequence is the same for Talos/Shikra/Agatti. The difference 
> between Talos and agatti when checked in the driver was the init load 
> settings. I checked with the hw team and they suggested using the init 
> load settings which talos was using.
> 
>   Hence both these compatibles (qcm2290 and qcs615) cannot be used as 
> fallback for Shikra.

Then I do not understand why you are using qcs615_usb3phy_cfg for
Shikra. You say that the initialization is different, but you use
exactly the same initialization. So in a meaning of compatibility
between hardware for Devicetree they are compatible.

Best regards,
Krzysztof

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* Re: [PATCH v2] phy: fsl-imx8mq-usb: set usb phy to be wakeup capable
From: sashiko-bot @ 2026-05-13 20:28 UTC (permalink / raw)
  To: Xu Yang; +Cc: olteanv, vkoul, Frank.Li, imx, neil.armstrong, linux-phy
In-Reply-To: <20260512101046.1498096-1-xu.yang_2@nxp.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] Missing error handling in the probe function leads to a Type-C switch leak and a critical Use-After-Free.
- [High] Using device_set_wakeup_capable() fails to enable wakeup by default, causing the PHY power domain to still be powered down during suspend.
- [High] Failing to enable the clocks in imx8mq_phy_power_on() leaves the vbus regulator permanently enabled.
--

commit c0b045ff9746b6affbecc02df5970fc02bc6a3ed
Author: Xu Yang <xu.yang_2@nxp.com>

phy: fsl-imx8mq-usb: set usb phy to be wakeup capable

The patch intends to keep the PHY power domain active during suspend
by setting the PHY to be wakeup capable.

> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index b05d80e849a14..b2e1e3749fc19 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> @@ -733,6 +733,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);

Will this successfully enable wakeup by default?

The PM domain framework (genpd) checks genpd_is_active_wakeup(genpd) and
device_awake_path(dev) (which depends on device_may_wakeup(dev)) to determine
if the domain should remain powered on.

device_may_wakeup(dev) evaluates to dev->power.can_wakeup &&
dev->power.should_wakeup. While device_set_wakeup_capable(dev, true) sets
can_wakeup = true, it leaves should_wakeup = false. As a result,
device_may_wakeup() returns false by default, and genpd will still power off
the PHY domain.

Should this use device_init_wakeup(dev, true) to enable it by default,
or should the USB subsystem dynamically propagate the controller's wakeup state
to the PHY instead?

>  	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

This isn't a bug introduced by this patch, but does this code leave a Type-C
switch registered if devm_of_phy_provider_register() fails?

If devm_of_phy_provider_register() returns an error, the probe function exits
without unregistering the Type-C switch (e.g., via imx95_usb_phy_put_tca()).
The imx_phy structure allocated with devm_kzalloc() would then be freed by the
driver core, but the switch remains active.

If the Type-C subsystem triggers the switch's set callback
(tca_blk_typec_switch_set()), it will access the freed imx_phy,
potentially resulting in a use-after-free.

>  
>  	return PTR_ERR_OR_ZERO(phy_provider);
>  }

This isn't a bug introduced by this patch, but does imx8mq_phy_power_on() leak
a regulator reference on error paths?

Looking at imx8mq_phy_power_on():

drivers/phy/freescale/phy-fsl-imx8mq-usb.c:imx8mq_phy_power_on() {
    ...
    ret = regulator_enable(imx_phy->vbus);
    if (ret)
        return ret;

    ret = clk_prepare_enable(imx_phy->clk);
    if (ret)
        return ret;
    ...
}

If clk_prepare_enable(imx_phy->clk) or clk_prepare_enable(imx_phy->alt_clk)
fails, the function returns directly without calling
regulator_disable(imx_phy->vbus).

Since the function returns an error, the PHY framework will not call
imx8mq_phy_power_off(). Could this leave the vbus regulator permanently
enabled?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512101046.1498096-1-xu.yang_2@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 v2] phy: fsl-imx8mq-usb: add control register regmap
From: sashiko-bot @ 2026-05-13 20:36 UTC (permalink / raw)
  To: Xu Yang; +Cc: linux-phy, vkoul, Frank.Li, neil.armstrong, imx, olteanv
In-Reply-To: <20260512101212.1498223-1-xu.yang_2@nxp.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Exporting the CR port regmap via debugfs without clock synchronization allows unclocked MMIO accesses, leading to a synchronous external abort (kernel panic).
- [Medium] Using a direct MMIO regmap for an indirect data/address parallel port does not correctly expose the internal PHY registers, defeating the diagnostic purpose of the patch.
--

commit ac06b61c8f793ff4f5693b009fbad15e95d82242
Author: Xu Yang <xu.yang_2@nxp.com>

phy: fsl-imx8mq-usb: add control register regmap

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.

> diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> index b05d80e849a14..958d114b0c835 100644
> --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
> +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
[ ... ]
> @@ -685,6 +689,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;
> @@ -713,6 +725,11 @@ 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);

Will accessing the debugfs file when the PHY is suspended or not yet powered
on cause a kernel panic?

The driver dynamically manages its clocks (imx_phy->clk and imx_phy->alt_clk)
in imx8mq_phy_power_on() and imx8mq_phy_power_off() rather than using
pm_runtime.

Since devm_regmap_init_mmio() does not attach a clock to the regmap,
the regmap core won't enable clocks during debugfs register accesses. On
i.MX platforms, MMIO reads on an unclocked hardware block trigger a
synchronous external abort.

Could we delegate clock management to the regmap (e.g., by using
devm_regmap_init_mmio_clk()) or implement pm_runtime hooks?

Additionally, the commit message mentions the CR port is a 16-bit
data/address parallel port used to access internal PHY registers. Does
this direct MMIO regmap actually expose the internal PHY registers?

Since devm_regmap_init_mmio() creates a direct memory-mapped regmap over
the CR port's base MMIO registers, reading the debugfs file will simply
dump the CR port's Address and Data MMIO registers. It won't execute the
required address/data handshake protocol to read the internal PHY state,
which defeats the diagnostic purpose of the patch.

Would it be better to implement a custom regmap_bus to handle the atomic
address/data indirect read sequence?

Also, is max_register = 0x7 correct here? It seems misleading for a 32-bit
regmap with a stride of 4 if there are only a couple of MMIO registers.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512101212.1498223-1-xu.yang_2@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 v4 2/5] phy: phy-can-transceiver: use device_get_match_data()
From: sashiko-bot @ 2026-05-13 21:26 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: vkoul, linux-phy, olteanv, neil.armstrong
In-Reply-To: <20260512130552.272476-3-andriy.shevchenko@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The error check for `device_get_match_data(dev)` is inverted, causing the driver probe to fail on success and triggering a NULL pointer dereference on failure.
--

commit f9915d9d74989682b2b7e20d67129e0dd4abdab9
Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

phy: phy-can-transceiver: use device_get_match_data()

This commit transitions the driver to use the generic firmware node interface
for retrieving device match data instead of the OF-specific one. It also drops
the unneeded device node argument from devm_phy_create().

> diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
> index 1808f903c0570..5cfd097352048 100644
> --- a/drivers/phy/phy-can-transceiver.c
> +++ b/drivers/phy/phy-can-transceiver.c
[ ... ]
> @@ -152,7 +152,6 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
>  	struct can_transceiver_phy *can_transceiver_phy;
>  	struct can_transceiver_priv *priv;
>  	const struct can_transceiver_data *drvdata;
> -	const struct of_device_id *match;
>  	struct phy *phy;
>  	struct gpio_desc *silent_gpio;
>  	struct gpio_desc *standby_gpio;
> @@ -161,11 +160,10 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
>  	u32 max_bitrate = 0;
>  	int err, i, num_ch = 1;
>  
> -	match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
> -	if (!match || !match->data)
> +	drvdata = device_get_match_data(dev);
> +	if (drvdata)
>  		return -ENODEV;

Does this invert the error check? 

When device_get_match_data() successfully returns valid match data, it looks
like this condition will evaluate to true and erroneously abort the probe with
-ENODEV.

>  
> -	drvdata = match->data;
>  	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
>  		num_ch = 2;

Conversely, if device_get_match_data() fails and returns NULL, won't the 
probe continue and cause a NULL pointer dereference when evaluating 
drvdata->flags here?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512130552.272476-1-andriy.shevchenko@linux.intel.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 v4 3/5] phy: phy-can-transceiver: Move OF ID table closer to their user
From: sashiko-bot @ 2026-05-13 21:31 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: neil.armstrong, vkoul, olteanv, linux-phy
In-Reply-To: <20260512130552.272476-4-andriy.shevchenko@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] The check `if (drvdata)` incorrectly returns `-ENODEV` when match data is found, and leads to a NULL pointer dereference when match data is missing.
--

commit e6497a416a7e21916ac93bad3296c090e87a31d4
Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

phy: phy-can-transceiver: Move OF ID table closer to their user

This commit moves the can_transceiver_phy_ids table closer to its
user at the end of the file.

> diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
> index 5cfd097352048..23655956ace80 100644
> --- a/drivers/phy/phy-can-transceiver.c
> +++ b/drivers/phy/phy-can-transceiver.c

[ ... ]

This regression wasn't introduced by this patch, but by a previous
commit in the series ("phy: phy-can-transceiver: use
device_get_match_data()").

Looking at can_transceiver_phy_probe(), does this code correctly handle the
match data?

drivers/phy/phy-can-transceiver.c:can_transceiver_phy_probe() {
    ...
	drvdata = device_get_match_data(dev);
	if (drvdata)
		return -ENODEV;

	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
    ...
}

It appears that if match data is successfully found, the probe will return
-ENODEV.

Conversely, if no match data is found, the condition evaluates to false,
and execution proceeds to dereference the NULL drvdata pointer.

Should the condition be changed to check for !drvdata instead?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512130552.272476-1-andriy.shevchenko@linux.intel.com?part=3

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* Re: [PATCH v4 4/5] phy: phy-can-transceiver: Don't check for specific errors when parsing properties
From: sashiko-bot @ 2026-05-13 21:38 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: vkoul, olteanv, linux-phy, neil.armstrong
In-Reply-To: <20260512130552.272476-5-andriy.shevchenko@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] The driver unconditionally fails or crashes due to incorrect checking of `drvdata`.
--

commit 64758b3de7d3ae700ae3ccdaef989d7410af4921
Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

phy: phy-can-transceiver: Don't check for specific errors when parsing properties

This commit modifies the max-bitrate property parsing to check for the
property existence first before attempting to read it. It applies a default
value if the property is missing, rather than relying on specific error
codes.

> diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
> index 23655956ace80..973cc7ce651fb 100644
> --- a/drivers/phy/phy-can-transceiver.c
> +++ b/drivers/phy/phy-can-transceiver.c
> @@ -128,8 +128,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
>  	struct gpio_desc *standby_gpio;
>  	struct gpio_desc *enable_gpio;
>  	struct mux_state *mux_state;
> -	u32 max_bitrate = 0;
>  	int err, i, num_ch = 1;
> +	const char *propname;
> +	u32 max_bitrate;
>  
>  	drvdata = device_get_match_data(dev);
>  	if (drvdata)

I noticed a potential issue in the context of this diff. Is the check for
drvdata inverted here? This logic appears to have been introduced by a
previous patch in the series.

If device_get_match_data() successfully finds match data, the probe function
aborts and returns -ENODEV. If no match data is found, drvdata is NULL and
the function proceeds, which leads to a dereference on the next check:

	drvdata = device_get_match_data(dev);
	if (drvdata)
		return -ENODEV;

	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
		num_ch = 2;

Could this cause the driver to fail on valid probes, or dereference a NULL
pointer when match data is missing?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512130552.272476-1-andriy.shevchenko@linux.intel.com?part=4

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* Re: [PATCH v4 5/5] phy: phy-can-transceiver: Drop unused include
From: sashiko-bot @ 2026-05-13 21:44 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: vkoul, olteanv, neil.armstrong, linux-phy
In-Reply-To: <20260512130552.272476-6-andriy.shevchenko@linux.intel.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The probe function incorrectly aborts when match data is found and dereferences a NULL pointer when match data is absent.
--

commit 8e35724d73ac65aed30d62ac9342ff1ac6be9401
Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

phy: phy-can-transceiver: Drop unused include

This commit removes the unused <linux/gpio.h> legacy header from the PHY CAN
transceiver driver, as its symbols are not used in the file. It also adjusts
the header order slightly.

> diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
> index 973cc7ce651fb..534a4fc482aa8 100644
> --- a/drivers/phy/phy-can-transceiver.c
> +++ b/drivers/phy/phy-can-transceiver.c
> @@ -5,12 +5,11 @@
>   * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
>   *
>   */
> +#include <linux/gpio/consumer.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  #include <linux/module.h>
> -#include <linux/gpio.h>
> -#include <linux/gpio/consumer.h>
>  #include <linux/mux/consumer.h>
>  
>  struct can_transceiver_data {

While reviewing this patch, I noticed an issue introduced earlier in the
series by commit "phy: phy-can-transceiver: use device_get_match_data()":

> --- a/drivers/phy/phy-can-transceiver.c
> +++ b/drivers/phy/phy-can-transceiver.c
[ ... ]
> @@ -161,11 +160,10 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
>  	u32 max_bitrate = 0;
>  	int err, i, num_ch = 1;
>  
> -	match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
> -	if (!match || !match->data)
> +	drvdata = device_get_match_data(dev);
> +	if (drvdata)
>  		return -ENODEV;
>  
> -	drvdata = match->data;
>  	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
>  		num_ch = 2;

Does this incorrectly abort the probe when match data is successfully found?
It looks like the condition is inverted, returning -ENODEV upon success.

Additionally, if match data is absent, drvdata will be NULL and execution
continues to the next line where it is dereferenced. Can this cause a NULL
pointer dereference?

Should the check be corrected to if (!drvdata)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512130552.272476-1-andriy.shevchenko@linux.intel.com?part=5

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* Re: [PATCH v4 2/5] phy: phy-can-transceiver: use device_get_match_data()
From: Andy Shevchenko @ 2026-05-13 21:51 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: vkoul, linux-phy, olteanv, neil.armstrong
In-Reply-To: <20260513212611.EDC78C19425@smtp.kernel.org>

On Wed, May 13, 2026 at 09:26:11PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The error check for `device_get_match_data(dev)` is inverted, causing the driver probe to fail on success and triggering a NULL pointer dereference on failure.

Right, the typo due to rebase. Will fix in v5.

-- 
With Best Regards,
Andy Shevchenko



-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* [PATCH v5 1/6] phy: phy-can-transceiver: Check driver match and driver data against NULL
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

Every platform driver can be forced to match a device that doesn't
match its list of device IDs because of device_match_driver_override()
so platform drivers that rely on the existence of a device's driver
data need to verify its presence.

Accordingly, add requisite match and driver data checks against NULL
to the driver where they are missing.

Fixes: a4a86d273ff1 ("phy: phy-can-transceiver: Add support for generic CAN transceiver driver")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 2b52e47f247a..1808f903c057 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -162,6 +162,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	int err, i, num_ch = 1;
 
 	match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
+	if (!match || !match->data)
+		return -ENODEV;
+
 	drvdata = match->data;
 	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
 		num_ch = 2;
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH v5 3/6] phy: phy-can-transceiver: Move OF ID table closer to their user
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

There is no code that uses ID table directly, except the
struct device_driver at the end of the file. Hence, move
table closer to its user. It's always possible to access
them via a pointer.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 58 +++++++++++++++----------------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 37b706d841ff..5c9698f77c7d 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -97,35 +97,6 @@ static const struct can_transceiver_data tja1057_drvdata = {
 	.flags = CAN_TRANSCEIVER_SILENT_PRESENT,
 };
 
-static const struct of_device_id can_transceiver_phy_ids[] = {
-	{
-		.compatible = "ti,tcan1042",
-		.data = &tcan1042_drvdata
-	},
-	{
-		.compatible = "ti,tcan1043",
-		.data = &tcan1043_drvdata
-	},
-	{
-		.compatible = "nxp,tja1048",
-		.data = &tja1048_drvdata
-	},
-	{
-		.compatible = "nxp,tja1051",
-		.data = &tja1051_drvdata
-	},
-	{
-		.compatible = "nxp,tja1057",
-		.data = &tja1057_drvdata
-	},
-	{
-		.compatible = "nxp,tjr1443",
-		.data = &tcan1043_drvdata
-	},
-	{ }
-};
-MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
-
 static struct phy *can_transceiver_phy_xlate(struct device *dev,
 					     const struct of_phandle_args *args)
 {
@@ -232,6 +203,35 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static const struct of_device_id can_transceiver_phy_ids[] = {
+	{
+		.compatible = "ti,tcan1042",
+		.data = &tcan1042_drvdata
+	},
+	{
+		.compatible = "ti,tcan1043",
+		.data = &tcan1043_drvdata
+	},
+	{
+		.compatible = "nxp,tja1048",
+		.data = &tja1048_drvdata
+	},
+	{
+		.compatible = "nxp,tja1051",
+		.data = &tja1051_drvdata
+	},
+	{
+		.compatible = "nxp,tja1057",
+		.data = &tja1057_drvdata
+	},
+	{
+		.compatible = "nxp,tjr1443",
+		.data = &tcan1043_drvdata
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
+
 static struct platform_driver can_transceiver_phy_driver = {
 	.probe = can_transceiver_phy_probe,
 	.driver = {
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH v5 0/6] phy: phy-can-transceiver: Ad-hoc cleanups and refactoring
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko


The driver does two things that need to be addressed:
- includes subject to remove gpio.h
- checks for error code from device property APIs when it can be done in
  a robust way

This series addresses the above and adds a couple of additional refactoring.

On top of that it fixes potential NULL pointer dereference when driver_override
is in use.

Changelog v5:
- fixed typo due to rebasing of patch 2 (Sashiko)
- added patch 5 to slightly improve maintainability

v4: 20260512130552.272476-1-andriy.shevchenko@linux.intel.com

Changelog v4:
- prepended the series with match and driver data check (Sashiko, Vinod)
- made the max_bitrate==0 warning only when property is present (Sashiko, Vinod)
- rebased the rest accordingly

v3: 20260504070054.29508-1-andriy.shevchenko@linux.intel.com

Changelog v3:
- fixed commit message in patch 1 (Josua)
- dropped stray change (Vinod)
- collected tags (Josua)

v2: 20260317203001.2108568-1-andriy.shevchenko@linux.intel.com

Changelog v2:
- rebased on top of the latest changes in the driver
- Cc'ed to Ulf and Josua due to above
- elaborated dropping of_node parameter (Vladimir)

v1: 20260219202910.2304440-1-andriy.shevchenko@linux.intel.com

*** BLURB HERE ***

Andy Shevchenko (6):
  phy: phy-can-transceiver: Check driver match and driver data against
    NULL
  phy: phy-can-transceiver: use device_get_match_data()
  phy: phy-can-transceiver: Move OF ID table closer to their user
  phy: phy-can-transceiver: Don't check for specific errors when parsing
    properties
  phy: phy-can-transceiver: Decouple assignment and definition in probe
  phy: phy-can-transceiver: Drop unused include

 drivers/phy/phy-can-transceiver.c | 93 +++++++++++++++++--------------
 1 file changed, 52 insertions(+), 41 deletions(-)

-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* [PATCH v5 2/6] phy: phy-can-transceiver: use device_get_match_data()
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

Use the generic firmware node interface for retrieving
device match data instead of the OF-specific one.

While at it, drop unneeded argument to devm_phy_create() which
extracts device node from the given device by default.

Reviewed-by: Josua Mayer <josua@solid-run.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 1808f903c057..37b706d841ff 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -5,9 +5,9 @@
  * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
  *
  */
-#include <linux/of.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
@@ -152,7 +152,6 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	struct can_transceiver_phy *can_transceiver_phy;
 	struct can_transceiver_priv *priv;
 	const struct can_transceiver_data *drvdata;
-	const struct of_device_id *match;
 	struct phy *phy;
 	struct gpio_desc *silent_gpio;
 	struct gpio_desc *standby_gpio;
@@ -161,11 +160,10 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	u32 max_bitrate = 0;
 	int err, i, num_ch = 1;
 
-	match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
-	if (!match || !match->data)
+	drvdata = device_get_match_data(dev);
+	if (!drvdata)
 		return -ENODEV;
 
-	drvdata = match->data;
 	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
 		num_ch = 2;
 
@@ -190,7 +188,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 		can_transceiver_phy = &priv->can_transceiver_phy[i];
 		can_transceiver_phy->priv = priv;
 
-		phy = devm_phy_create(dev, dev->of_node, &can_transceiver_phy_ops);
+		phy = devm_phy_create(dev, NULL, &can_transceiver_phy_ops);
 		if (IS_ERR(phy)) {
 			dev_err(dev, "failed to create can transceiver phy\n");
 			return PTR_ERR(phy);
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH v5 4/6] phy: phy-can-transceiver: Don't check for specific errors when parsing properties
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

Instead of checking for the specific error codes (that can be considered
a layering violation to some extent) check for the property existence first
and then either parse it, or apply a default value.

With that, return an error when parsing of the existing property fails.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 5c9698f77c7d..3cebaa54f7db 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -128,8 +128,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	struct gpio_desc *standby_gpio;
 	struct gpio_desc *enable_gpio;
 	struct mux_state *mux_state;
-	u32 max_bitrate = 0;
 	int err, i, num_ch = 1;
+	const char *propname;
+	u32 max_bitrate;
 
 	drvdata = device_get_match_data(dev);
 	if (!drvdata)
@@ -151,9 +152,17 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 
 	priv->mux_state = mux_state;
 
-	err = device_property_read_u32(dev, "max-bitrate", &max_bitrate);
-	if ((err != -EINVAL) && !max_bitrate)
-		dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
+	propname = "max-bitrate";
+	if (device_property_present(dev, propname)) {
+		err = device_property_read_u32(dev, propname, &max_bitrate);
+		if (err)
+			return dev_err_probe(dev, err, "failed to parse %s\n", propname);
+
+		if (max_bitrate == 0)
+			dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
+	} else {
+		max_bitrate = 0;
+	}
 
 	for (i = 0; i < num_ch; i++) {
 		can_transceiver_phy = &priv->can_transceiver_phy[i];
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH v5 6/6] phy: phy-can-transceiver: Drop unused include
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

This file does not use the symbols from the legacy
<linux/gpio.h> header, so let's drop it.

Reviewed-by: Josua Mayer <josua@solid-run.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 30330499585b..75dc49e75ca0 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -5,12 +5,11 @@
  * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
  *
  */
+#include <linux/gpio/consumer.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/gpio/consumer.h>
 #include <linux/mux/consumer.h>
 
 struct can_transceiver_data {
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH v5 5/6] phy: phy-can-transceiver: Decouple assignment and definition in probe
From: Andy Shevchenko @ 2026-05-13 22:01 UTC (permalink / raw)
  To: Peng Fan, linux-can, linux-phy, linux-kernel
  Cc: Marc Kleine-Budde, Vincent Mailhol, Vinod Koul, Neil Armstrong,
	Josua Mayer, Ulf Hansson, Andy Shevchenko
In-Reply-To: <20260513220336.369628-1-andriy.shevchenko@linux.intel.com>

The code like

	int foo = X;
	...
	if (bar)
		foo = Y;

is prone to subtle mistakes and hence harder to maintain as the foo value
may be changed inadvertently while code in '...' grown in lines. On top
it's harder to navigate to understand the possible values of foo when branch
is not taken (requires to look somewhere else in the code, far from the piece
at hand).

Besides that in case of taken branch the foo will be rewritten, which is
not a problem per se, just an unneeded operation.

Decouple assignment and definition to use if-else to address the inconveniences
described above.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/phy/phy-can-transceiver.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index 3cebaa54f7db..30330499585b 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -128,8 +128,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 	struct gpio_desc *standby_gpio;
 	struct gpio_desc *enable_gpio;
 	struct mux_state *mux_state;
-	int err, i, num_ch = 1;
 	const char *propname;
+	int err, i, num_ch;
 	u32 max_bitrate;
 
 	drvdata = device_get_match_data(dev);
@@ -138,6 +138,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 
 	if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH)
 		num_ch = 2;
+	else
+		num_ch = 1;
 
 	priv = devm_kzalloc(dev, struct_size(priv, can_transceiver_phy, num_ch), GFP_KERNEL);
 	if (!priv)
-- 
2.50.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* Re: [PATCH v1 2/6] usb: chipidea: tegra: Avoid controller/PHY init if bus is externally controlled
From: Peter Chen (CIX) @ 2026-05-14  1:42 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Vinod Koul, Neil Armstrong, Thierry Reding, Jonathan Hunter,
	Greg Kroah-Hartman, netdev, devicetree, linux-kernel, linux-phy,
	linux-tegra, linux-usb
In-Reply-To: <CAPVz0n2yGALm1Z0j0j6_MaqAOZGL+a8EgCWYQpW0QN1YVf96EQ@mail.gmail.com>

On 26-05-13 20:30:10, Svyatoslav Ryhel wrote:
> вт, 12 трав. 2026 р. о 10:51 Peter Chen (CIX) <peter.chen@kernel.org> пише:
> >
> > On 26-05-12 09:13:40, Svyatoslav Ryhel wrote:
> > > вт, 12 трав. 2026 р. о 04:16 Peter Chen (CIX) <peter.chen@kernel.org> пише:
> > > >
> > > > On 26-05-11 16:56:57, Svyatoslav Ryhel wrote:
> > > > > If the USB controller and PHY are externally controlled, then the
> > > > > registration of the controller and the PHY initialization should be
> > > > > skipped, since these configurations must be done by the device that
> > > > > controls the bus to work correctly.
> > > > >
> > > >
> > > > I find you only control USB controller device add at PHY driver, most of USB drivers
> > > > has PHY control, for chipidea, it has PHY control at core.c, would please try to
> > > > adapt for it?
> > > >
> > >
> > > Usually yes, but this is not the case for Tegra unfortunately. As you
> > > can see Tegra specific section of Chipidea driver specifically
> > > describes why it has to set PHY manually.
> > >
> > > /*
> > >  * USB controller registers shouldn't be touched before PHY is
> > >  * initialized, otherwise CPU will hang because clocks are gated.
> > >  * PHY driver controls gating of internal USB clocks on Tegra.
> > >  */
> > >
> > > So in order to provide correct work of USB when set by an external
> > > device, both PHY and controller init/add must be skipped.
> >
> > You could call generic PHY APIs at ci_hdrc_tegra.c, after PHY init or power on,
> > call controller initialization.
> >
> 
> I was tinkering with Chipidea driver for Tegra a bit. If you meant to
> use flag only to control usb controller device init and leave PHY to
> be handled by controller, then yes, that is possible and that is
> better approach.
> 

Yes, you may summarize the initialization sequence, and see if put PHY
control at Tegra glue layer or at Chipidea core.

-- 

Best regards,
Peter

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* Re: [PATCH] phy: ti: pipe3: Fix clock resource leak on probe errors
From: sashiko-bot @ 2026-05-14  2:10 UTC (permalink / raw)
  To: Hongling Zeng; +Cc: linux-phy, vkoul, neil.armstrong, olteanv
In-Reply-To: <20260513063902.113956-1-zenghongling@kylinos.cn>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing pm_runtime_disable() in the probe error path leaves PM runtime state unbalanced.
--

commit fd04e6bd036402bf170a7ff7978b95f1478bfd7b
Author: Hongling Zeng <zenghongling@kylinos.cn>

phy: ti: pipe3: Fix clock resource leak on probe errors

This commit addresses a clock resource leak in the probe error path of the
TI PIPE3 PHY driver. It adds an err_clk_disable label to ensure the reference
clock is disabled if PHY creation or provider registration fails.

> diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c
> index b5543b5c674c8..29a4cbe737812 100644
> --- a/drivers/phy/ti/phy-ti-pipe3.c
> +++ b/drivers/phy/ti/phy-ti-pipe3.c
> @@ -837,15 +837,27 @@ static int ti_pipe3_probe(struct platform_device *pdev)

[ ... ]

>  	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> -	return PTR_ERR_OR_ZERO(phy_provider);
> +	if (IS_ERR(phy_provider)) {
> +		ret = PTR_ERR(phy_provider);
> +		goto err_clk_disable;
> +	}
> +
> +	return 0;
> +
> +err_clk_disable:
> +	if (phy->sata_refclk_enabled)
> +		clk_disable_unprepare(phy->refclk);
> +	return ret;

Does this new error path leave the power management runtime state unbalanced?

Earlier in ti_pipe3_probe(), pm_runtime_enable(dev) is called. Without a
corresponding pm_runtime_disable() call in this error path, it looks like
the device's power management runtime state is left unbalanced, which can
trigger a warning on subsequent probe retries.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260513063902.113956-1-zenghongling@kylinos.cn?part=1

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply

* [PATCH v2] phy: ti: pipe3: Fix clock resource leak on probe errors
From: Hongling Zeng @ 2026-05-14  2:34 UTC (permalink / raw)
  To: vkoul, neil.armstrong, johan, kishon
  Cc: linux-phy, linux-kernel, zhongling0719, Hongling Zeng

When devm_phy_create() or devm_of_phy_provider_register() fails,
the refclk that was enabled earlier is not disabled, causing a
resource leak.

Fix this by adding an error handling path to disable the clock
when these functions fail.

Fixes: 234738ea3390 ("phy: ti-pipe3: move clk initialization to a separate function")
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>

---
 Change in v2:
  -Add pm_runtime_disable() in error path (reported by Sashiko AI).
---
 drivers/phy/ti/phy-ti-pipe3.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c
index b5543b5c674c..5f4a81f6d2b9 100644
--- a/drivers/phy/ti/phy-ti-pipe3.c
+++ b/drivers/phy/ti/phy-ti-pipe3.c
@@ -837,15 +837,28 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 	}
 
 	generic_phy = devm_phy_create(dev, NULL, &ops);
-	if (IS_ERR(generic_phy))
-		return PTR_ERR(generic_phy);
+	if (IS_ERR(generic_phy)) {
+		ret = PTR_ERR(generic_phy);
+		goto err_clk_disable;
+	}
 
 	phy_set_drvdata(generic_phy, phy);
 
 	ti_pipe3_power_off(generic_phy);
 
 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-	return PTR_ERR_OR_ZERO(phy_provider);
+	if (IS_ERR(phy_provider)) {
+		ret = PTR_ERR(phy_provider);
+		goto err_clk_disable;
+	}
+
+	return 0;
+
+err_clk_disable:
+	pm_runtime_disable(dev);
+	if (phy->sata_refclk_enabled)
+		clk_disable_unprepare(phy->refclk);
+	return ret;
 }
 
 static void ti_pipe3_remove(struct platform_device *pdev)
-- 
2.25.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related

* [PATCH 0/2] Enable the QMP PCIe PHY present in Qualcomm ipq5210 SoC
From: Varadarajan Narayanan @ 2026-05-14  3:58 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel,
	Varadarajan Narayanan

Document the bindings and update the driver to support
the PCIe phy present in Qualcomm ipq5210 SoC.

Signed-off-by: Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>
---
Varadarajan Narayanan (2):
      dt-bindings: phy: qcom,ipq8074-qmp-pcie: Document the ipq5210 QMP PCIe PHY
      phy: qcom-qmp-pcie: Add support for ipq5210 PCIe phys

 .../bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml    |   3 +
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c           | 152 +++++++++++++++++++++
 2 files changed, 155 insertions(+)
---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260514-pci-phy-38ec9b1c5a90

Best regards,
-- 
Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>


-- 
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,ipq8074-qmp-pcie: Document the ipq5210 QMP PCIe PHY
From: Varadarajan Narayanan @ 2026-05-14  3:58 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel,
	Varadarajan Narayanan
In-Reply-To: <20260514-pci-phy-v1-0-482429192746@oss.qualcomm.com>

Document the PCIe phy on the ipq5210 platform using the ipq9574 bindings
as a fallback, since the PCIe phy on the ipq5210 is similar to ipq9574.

Signed-off-by: Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml
index f60804687412..1ac31439c20a 100644
--- a/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,ipq8074-qmp-pcie-phy.yaml
@@ -17,6 +17,7 @@ properties:
   compatible:
     oneOf:
       - enum:
+          - qcom,ipq5210-qmp-gen3x1-pcie-phy
           - qcom,ipq6018-qmp-pcie-phy
           - qcom,ipq8074-qmp-gen3-pcie-phy
           - qcom,ipq8074-qmp-pcie-phy
@@ -24,10 +25,12 @@ properties:
           - qcom,ipq9574-qmp-gen3x2-pcie-phy
       - items:
           - enum:
+              - qcom,ipq5210-qmp-gen3x1-pcie-phy
               - qcom,ipq5424-qmp-gen3x1-pcie-phy
           - const: qcom,ipq9574-qmp-gen3x1-pcie-phy
       - items:
           - enum:
+              - qcom,ipq5210-qmp-gen3x2-pcie-phy
               - qcom,ipq5424-qmp-gen3x2-pcie-phy
           - const: qcom,ipq9574-qmp-gen3x2-pcie-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

* [PATCH 2/2] phy: qcom-qmp-pcie: Add support for ipq5210 PCIe phys
From: Varadarajan Narayanan @ 2026-05-14  3:58 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel,
	Varadarajan Narayanan
In-Reply-To: <20260514-pci-phy-v1-0-482429192746@oss.qualcomm.com>

Add support for a PCIe phys found on Qualcomm ipq5210 platform.

Signed-off-by: Varadarajan Narayanan <varadarajan.narayanan@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 152 +++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index fed2fc9bb311..5887306eb67b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -514,6 +514,105 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_misc_tbl[] = {
 	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
 };
 
+static const struct qmp_phy_init_tbl ipq5210_gen3x1_pcie_ep_serdes_tbl[] = {
+	QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TIMER, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xff),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x04),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xff),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x09),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x23),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x23),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x10),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x10),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x00),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x19),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xfe),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE0, 0x03),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xfe),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE1, 0x03),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x10),
+};
+
+static const struct qmp_phy_init_tbl ipq5210_gen3x1_pcie_ep_tx_tbl[] = {
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12),
+};
+
+static const struct qmp_phy_init_tbl ipq5210_gen3x1_pcie_ep_rx_tbl[] = {
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x70),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x61),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1e),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x73),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x03),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xf0),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x2f),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0xd3),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x40),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xc8),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x09),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb1),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0x00),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xc8),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x09),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0xb1),
+	QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04),
+};
+
+static const struct qmp_phy_init_tbl ipq5210_gen3x1_pcie_ep_pcs_tbl[] = {
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_FLL_CNTRL1, 0x01),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x01),
+};
+
+static const struct qmp_phy_init_tbl ipq5210_gen3x1_pcie_ep_pcs_misc_tbl[] = {
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG2, 0x04),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG1, 0x11),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_PRE, 0x00),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_POST, 0x58),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_CONFIG1, 0x02),
+	QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_CONFIG4, 0xff),
+};
+
 static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_serdes_tbl[] = {
 	QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18),
 	QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01),
@@ -654,6 +753,13 @@ static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_serdes_tbl[] = {
 	QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x10),
 };
 
+static const struct qmp_phy_init_tbl ipq9574_pcie_tx_tbl[] = {
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12),
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_HIGHZ_DRVR_EN, 0x10),
+	QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x06),
+};
+
 static const struct qmp_phy_init_tbl ipq9574_pcie_rx_tbl[] = {
 	QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x03),
 	QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x1c),
@@ -3613,6 +3719,49 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
 	.phy_status		= PHYSTATUS,
 };
 
+static const struct qmp_phy_cfg ipq5210_gen3x1_pciephy_cfg = {
+	.lanes			= 1,
+
+	.offsets		= &qmp_pcie_offsets_v4x1,
+
+	.tbls =  {
+		.serdes		= ipq9574_gen3x1_pcie_serdes_tbl,
+		.serdes_num	= ARRAY_SIZE(ipq9574_gen3x1_pcie_serdes_tbl),
+		.tx		= ipq9574_pcie_tx_tbl,
+		.tx_num		= ARRAY_SIZE(ipq9574_pcie_tx_tbl),
+		.rx		= ipq9574_pcie_rx_tbl,
+		.rx_num		= ARRAY_SIZE(ipq9574_pcie_rx_tbl),
+		.pcs		= ipq9574_gen3x1_pcie_pcs_tbl,
+		.pcs_num	= ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_tbl),
+		.pcs_misc	= ipq9574_gen3x1_pcie_pcs_misc_tbl,
+		.pcs_misc_num	= ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_misc_tbl),
+	},
+
+	.tbls_ep = &(const struct qmp_phy_cfg_tbls) {
+		.serdes		= ipq5210_gen3x1_pcie_ep_serdes_tbl,
+		.serdes_num	= ARRAY_SIZE(ipq5210_gen3x1_pcie_ep_serdes_tbl),
+		.tx		= ipq5210_gen3x1_pcie_ep_tx_tbl,
+		.tx_num		= ARRAY_SIZE(ipq5210_gen3x1_pcie_ep_tx_tbl),
+		.rx		= ipq5210_gen3x1_pcie_ep_rx_tbl,
+		.rx_num		= ARRAY_SIZE(ipq5210_gen3x1_pcie_ep_rx_tbl),
+		.pcs		= ipq5210_gen3x1_pcie_ep_pcs_tbl,
+		.pcs_num	= ARRAY_SIZE(ipq5210_gen3x1_pcie_ep_pcs_tbl),
+		.pcs_misc	= ipq5210_gen3x1_pcie_ep_pcs_misc_tbl,
+		.pcs_misc_num	= ARRAY_SIZE(ipq5210_gen3x1_pcie_ep_pcs_misc_tbl),
+	},
+
+	.reset_list		= ipq8074_pciephy_reset_l,
+	.num_resets		= ARRAY_SIZE(ipq8074_pciephy_reset_l),
+	.vreg_list		= NULL,
+	.num_vregs		= 0,
+	.regs			= pciephy_v4_regs_layout,
+
+	.pwrdn_ctrl		= SW_PWRDN | REFCLK_DRV_DSBL,
+	.phy_status		= PHYSTATUS,
+
+	.pipe_clock_rate	= 250000000,
+};
+
 static const struct qmp_phy_cfg ipq9574_gen3x1_pciephy_cfg = {
 	.lanes			= 1,
 
@@ -5404,6 +5553,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
 	}, {
 		.compatible = "qcom,glymur-qmp-gen5x4-pcie-phy",
 		.data = &glymur_qmp_gen5x4_pciephy_cfg,
+	}, {
+		.compatible = "qcom,ipq5210-qmp-gen3x1-pcie-phy",
+		.data = &ipq5210_gen3x1_pciephy_cfg,
 	}, {
 		.compatible = "qcom,ipq6018-qmp-pcie-phy",
 		.data = &ipq6018_pciephy_cfg,

-- 
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 v5 1/2] dt-bindings: phy: add support for NXPs TJA1145 CAN transceiver
From: sashiko-bot @ 2026-05-14  5:17 UTC (permalink / raw)
  To: Dimitri Fedrau via B4 Relay
  Cc: linux-phy, conor+dt, devicetree, vkoul, olteanv, robh,
	neil.armstrong, krzk+dt
In-Reply-To: <20260513-tja1145-support-v5-1-38720a7ee63e@liebherr.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The dt-binding omits support for the `max-bitrate` property.
- [Medium] The dt-binding omits support for the `interrupts` property for wake-up routing.
--

commit 853ad7c93ebe1c2a625ddddde401c4aaad496a8e
Author: Dimitri Fedrau <dimitri.fedrau@liebherr.com>

dt-bindings: phy: add support for NXPs TJA1145 CAN transceiver

This commit adds documentation for the NXP TJA1145 CAN transceiver, residing
in the generic PHY subsystem bindings. It describes the required SPI
configurations and supply properties for the device.

> diff --git a/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml b/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml
> new file mode 100644
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/nxp,tja1145.yaml

[ ... ]

> +  vbat-supply:
> +    description:
> +      Battery supply voltage
> +
> +required:
> +  - compatible
> +  - reg
> +  - "#phy-cells"
> +  - spi-cpha
> +
> +additionalProperties: false

Does this binding need to include the max-bitrate property?

This property is standard for CAN transceivers to describe board-level
capability constraints where the layout cannot support the chip's theoretical
maximum speed. Since additionalProperties is set to false, valid device trees
specifying a maximum bitrate will fail validation.

Also, does this device tree binding need support for the interrupts property?

The TJA1145 supports partial networking and wake-up functionality, which can
route a wake-up signal to an interrupt line on the host processor. With
additionalProperties set to false, it is impossible to describe this hardware
interrupt routing in the device tree.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260513-tja1145-support-v5-0-38720a7ee63e@liebherr.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 v5 2/2] phy: add basic support for NXPs TJA1145 CAN transceiver
From: sashiko-bot @ 2026-05-14  5:44 UTC (permalink / raw)
  To: Dimitri Fedrau via B4 Relay
  Cc: olteanv, krzk+dt, vkoul, linux-phy, conor+dt, robh, devicetree,
	neil.armstrong
In-Reply-To: <20260513-tja1145-support-v5-2-38720a7ee63e@liebherr.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The driver fails to enable the hardware power supplies (`vcc-supply`, `vio-supply`, `vbat-supply`) before communicating with the device.
- [High] The driver does not observe the required mode transition delay when powering on the PHY.
- [Medium] Missing rollback to standby mode in the error path of `tja1145_phy_power_on`.
--

commit 288134e179992cb2e690ff7a97502e72f04e9d5a
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 implements the PHY operations to bring the hardware up and 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;

According to the hardware datasheet, transitioning the transceiver to normal
mode can take up to 40 us. Does this sequence need a hardware transition
delay before sending the active mode command?

With a fast SPI bus, the next command might arrive before the hardware state
machine finishes transitioning, which could cause the active mode command to
be ignored.

> +
> +	/*
> +	 * 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);

If this second regmap_update_bits() fails, the function returns an error
without reverting the device to standby mode.

Since the PHY framework keeps the power_count at 0 on an error return,
phy_power_off() will not be called during shutdown or suspend. Could this
leave the hardware permanently stuck in normal mode, drawing power
unintentionally?

> +}

[ ... ]

> +static int tja1145_probe(struct spi_device *spi)
> +{
> +	struct phy_provider *phy_provider;
> +	struct device *dev = &spi->dev;
> +	struct regmap *map;
> +	struct phy *phy;
> +	int ret;
> +
> +	map = devm_regmap_init_spi(spi, &tja1145_regmap_config);
> +	if (IS_ERR(map))
> +		return dev_err_probe(dev, PTR_ERR(map), "failed to init regmap\n");
> +
> +	ret = tja1145_check_ident(dev, map);

Will this fail to communicate with the hardware on platforms where power
supplies are dynamically controlled?

The device tree binding defines vcc-supply, vio-supply, and vbat-supply as
power sources, but they do not appear to be requested or enabled in this
function before tja1145_check_ident() is called.

This might leave the PHY unpowered, causing the SPI read to return garbage
data and fail the probe with -ENODEV.

> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to identify device\n");

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260513-tja1145-support-v5-0-38720a7ee63e@liebherr.com?part=2

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox