From: Geert Uytterhoeven Date: Mon, 24 Nov 2025 10:28:32 +0000 (+0000) Subject: can: rcar_canfd: Add suspend/resume support X-Git-Tag: v6.19-rc1~170^2~49^2~2^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3a34330f6339641b7f5b76b066385f56c114490f;p=thirdparty%2Fkernel%2Flinux.git can: rcar_canfd: Add suspend/resume support 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 Tested-by: Biju Das Signed-off-by: Biju Das Link: https://patch.msgid.link/20251124102837.106973-8-biju.das.jz@bp.renesas.com Signed-off-by: Marc Kleine-Budde --- diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 1d6b2f7efa8cb..ce75948e6af63 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -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; }