can: flexcan: add transceiver capabilities
authorDimitri Fedrau <dimitri.fedrau@liebherr.com>
Wed, 12 Mar 2025 17:45:23 +0000 (18:45 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 14 Mar 2025 08:37:22 +0000 (09:37 +0100)
Currently the flexcan driver does only support adding PHYs by using the
"old" regulator bindings. Add support for CAN transceivers as a PHY. Add
the capability to ensure that the PHY is in operational state when the link
is set to an "up" state.

Signed-off-by: Dimitri Fedrau <dimitri.fedrau@liebherr.com>
Link: https://patch.msgid.link/20250312-flexcan-add-transceiver-caps-v4-2-29e89ae0225a@liebherr.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/flexcan/flexcan-core.c
drivers/net/can/flexcan/flexcan.h

index b347a1c93536d54efaa5f7d3347bd47c20860b3e..7588cb54a909af065522ddbcb06cc3acb9669893 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/can/platform/flexcan.h>
+#include <linux/phy/phy.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
@@ -644,18 +645,22 @@ static void flexcan_clks_disable(const struct flexcan_priv *priv)
 
 static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
 {
-       if (!priv->reg_xceiver)
-               return 0;
+       if (priv->reg_xceiver)
+               return regulator_enable(priv->reg_xceiver);
+       else if (priv->transceiver)
+               return phy_power_on(priv->transceiver);
 
-       return regulator_enable(priv->reg_xceiver);
+       return 0;
 }
 
 static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
 {
-       if (!priv->reg_xceiver)
-               return 0;
+       if (priv->reg_xceiver)
+               return regulator_disable(priv->reg_xceiver);
+       else if (priv->transceiver)
+               return phy_power_off(priv->transceiver);
 
-       return regulator_disable(priv->reg_xceiver);
+       return 0;
 }
 
 static int flexcan_chip_enable(struct flexcan_priv *priv)
@@ -2086,6 +2091,7 @@ static int flexcan_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct flexcan_priv *priv;
        struct regulator *reg_xceiver;
+       struct phy *transceiver;
        struct clk *clk_ipg = NULL, *clk_per = NULL;
        struct flexcan_regs __iomem *regs;
        struct flexcan_platform_data *pdata;
@@ -2101,6 +2107,11 @@ static int flexcan_probe(struct platform_device *pdev)
        else if (IS_ERR(reg_xceiver))
                return PTR_ERR(reg_xceiver);
 
+       transceiver = devm_phy_optional_get(&pdev->dev, NULL);
+       if (IS_ERR(transceiver))
+               return dev_err_probe(&pdev->dev, PTR_ERR(transceiver),
+                                    "failed to get phy\n");
+
        if (pdev->dev.of_node) {
                of_property_read_u32(pdev->dev.of_node,
                                     "clock-frequency", &clock_freq);
@@ -2198,6 +2209,10 @@ static int flexcan_probe(struct platform_device *pdev)
        priv->clk_per = clk_per;
        priv->clk_src = clk_src;
        priv->reg_xceiver = reg_xceiver;
+       priv->transceiver = transceiver;
+
+       if (transceiver)
+               priv->can.bitrate_max = transceiver->attrs.max_link_rate;
 
        if (priv->devtype_data.quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
                priv->irq_boff = platform_get_irq(pdev, 1);
index 2cf886618c9621166173b865f266830b3f6c1fb0..16692a2502eba26575eeeec83dfffdf35f07b034 100644 (file)
@@ -107,6 +107,7 @@ struct flexcan_priv {
        struct clk *clk_per;
        struct flexcan_devtype_data devtype_data;
        struct regulator *reg_xceiver;
+       struct phy *transceiver;
        struct flexcan_stop_mode stm;
 
        int irq_boff;