can: rcar_canfd: Add transceiver support
authorGeert Uytterhoeven <geert+renesas@glider.be>
Tue, 21 Mar 2023 16:15:00 +0000 (17:15 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 24 Mar 2023 18:07:16 +0000 (19:07 +0100)
Add support for CAN transceivers described as PHYs.

While simple CAN transceivers can do without, this is needed for CAN
transceivers like NXP TJR1443 that need a configuration step (like
pulling standby or enable lines), and/or impose a bitrate limit.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://lore.kernel.org/all/1ce907572ac1d4e1733fa6ea7712250f2229cfcb.1679414936.git.geert+renesas@glider.be
[mkl: squash error message update from patch 2]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/rcar/rcar_canfd.c

index ef4e1b9a9e1ee280a4e54565d7c42619da57d337..d8fbc3fca4759d052cb4941ffb889c8ef79b70f3 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/netdevice.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 #include <linux/types.h>
@@ -530,6 +531,7 @@ struct rcar_canfd_channel {
        struct net_device *ndev;
        struct rcar_canfd_global *gpriv;        /* Controller reference */
        void __iomem *base;                     /* Register base address */
+       struct phy *transceiver;                /* Optional transceiver */
        struct napi_struct napi;
        u32 tx_head;                            /* Incremented on xmit */
        u32 tx_tail;                            /* Incremented on xmit done */
@@ -1413,11 +1415,17 @@ static int rcar_canfd_open(struct net_device *ndev)
        struct rcar_canfd_global *gpriv = priv->gpriv;
        int err;
 
+       err = phy_power_on(priv->transceiver);
+       if (err) {
+               netdev_err(ndev, "failed to power on PHY: %pe\n", ERR_PTR(err));
+               return err;
+       }
+
        /* Peripheral clock is already enabled in probe */
        err = clk_prepare_enable(gpriv->can_clk);
        if (err) {
                netdev_err(ndev, "failed to enable CAN clock, error %d\n", err);
-               goto out_clock;
+               goto out_phy;
        }
 
        err = open_candev(ndev);
@@ -1437,7 +1445,8 @@ out_close:
        close_candev(ndev);
 out_can_clock:
        clk_disable_unprepare(gpriv->can_clk);
-out_clock:
+out_phy:
+       phy_power_off(priv->transceiver);
        return err;
 }
 
@@ -1480,6 +1489,7 @@ static int rcar_canfd_close(struct net_device *ndev)
        napi_disable(&priv->napi);
        clk_disable_unprepare(gpriv->can_clk);
        close_candev(ndev);
+       phy_power_off(priv->transceiver);
        return 0;
 }
 
@@ -1711,7 +1721,7 @@ static const struct ethtool_ops rcar_canfd_ethtool_ops = {
 };
 
 static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
-                                   u32 fcan_freq)
+                                   u32 fcan_freq, struct phy *transceiver)
 {
        const struct rcar_canfd_hw_info *info = gpriv->info;
        struct platform_device *pdev = gpriv->pdev;
@@ -1732,8 +1742,11 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
        ndev->flags |= IFF_ECHO;
        priv->ndev = ndev;
        priv->base = gpriv->base;
+       priv->transceiver = transceiver;
        priv->channel = ch;
        priv->gpriv = gpriv;
+       if (transceiver)
+               priv->can.bitrate_max = transceiver->attrs.max_link_rate;
        priv->can.clock.freq = fcan_freq;
        dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq);
 
@@ -1836,6 +1849,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
 
 static int rcar_canfd_probe(struct platform_device *pdev)
 {
+       struct phy *transceivers[RCANFD_NUM_CHANNELS] = { 0, };
        const struct rcar_canfd_hw_info *info;
        struct device *dev = &pdev->dev;
        void __iomem *addr;
@@ -1857,9 +1871,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
        for (i = 0; i < info->max_channels; ++i) {
                name[7] = '0' + i;
                of_child = of_get_child_by_name(dev->of_node, name);
-               if (of_child && of_device_is_available(of_child))
+               if (of_child && of_device_is_available(of_child)) {
                        channels_mask |= BIT(i);
+                       transceivers[i] = devm_of_phy_optional_get(dev,
+                                                       of_child, NULL);
+               }
                of_node_put(of_child);
+               if (IS_ERR(transceivers[i]))
+                       return PTR_ERR(transceivers[i]);
        }
 
        if (info->shared_global_irqs) {
@@ -2035,7 +2054,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
        }
 
        for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
-               err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq);
+               err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
+                                              transceivers[ch]);
                if (err)
                        goto fail_channel;
        }