]> Gentwo Git Trees - linux/.git/commitdiff
can: rcar_canfd: Add suspend/resume support
authorGeert Uytterhoeven <geert+renesas@glider.be>
Mon, 24 Nov 2025 10:28:32 +0000 (10:28 +0000)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 26 Nov 2025 10:21:56 +0000 (11:21 +0100)
On R-Car Gen3 using PSCI, s2ram powers down the SoC.  After resume, the
CAN-FD interface no longer works.  Trying to bring it up again fails:

    # ip link set can0 up
    RTNETLINK answers: Connection timed out

    # dmesg
    ...
    channel 0 communication state failed

Fix this by populating the (currently empty) suspend and resume
callbacks, to stop/start the individual CAN-FD channels, and
(de)initialize the CAN-FD controller.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Tested-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20251124102837.106973-8-biju.das.jz@bp.renesas.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/rcar/rcar_canfd.c

index 1d6b2f7efa8cb2edcefce721e62c0edfaa6b7850..ce75948e6af635d9df0c1a8183a2c5853eba67a7 100644 (file)
@@ -2257,11 +2257,64 @@ static void rcar_canfd_remove(struct platform_device *pdev)
 
 static int rcar_canfd_suspend(struct device *dev)
 {
+       struct rcar_canfd_global *gpriv = dev_get_drvdata(dev);
+       int err;
+       u32 ch;
+
+       for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+               struct rcar_canfd_channel *priv = gpriv->ch[ch];
+               struct net_device *ndev = priv->ndev;
+
+               if (!netif_running(ndev))
+                       continue;
+
+               netif_device_detach(ndev);
+
+               err = rcar_canfd_close(ndev);
+               if (err) {
+                       netdev_err(ndev, "rcar_canfd_close() failed %pe\n",
+                                  ERR_PTR(err));
+                       return err;
+               }
+
+               priv->can.state = CAN_STATE_SLEEPING;
+       }
+
+       /* TODO Skip if wake-up (which is not yet supported) is enabled */
+       rcar_canfd_global_deinit(gpriv, false);
+
        return 0;
 }
 
 static int rcar_canfd_resume(struct device *dev)
 {
+       struct rcar_canfd_global *gpriv = dev_get_drvdata(dev);
+       int err;
+       u32 ch;
+
+       err = rcar_canfd_global_init(gpriv);
+       if (err) {
+               dev_err(dev, "rcar_canfd_global_init() failed %pe\n", ERR_PTR(err));
+               return err;
+       }
+
+       for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+               struct rcar_canfd_channel *priv = gpriv->ch[ch];
+               struct net_device *ndev = priv->ndev;
+
+               if (!netif_running(ndev))
+                       continue;
+
+               err = rcar_canfd_open(ndev);
+               if (err) {
+                       netdev_err(ndev, "rcar_canfd_open() failed %pe\n",
+                                  ERR_PTR(err));
+                       return err;
+               }
+
+               netif_device_attach(ndev);
+       }
+
        return 0;
 }