Extract the code to (de)initialize global state into separate functions, for future reuse. Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx> --- drivers/net/can/rcar/rcar_canfd.c | 160 +++++++++++++++++------------- 1 file changed, 93 insertions(+), 67 deletions(-) diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 341bc25df32a8973..38c1b327f6b1d540 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -1950,22 +1950,110 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch) } } +static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv) +{ + struct device *dev = &gpriv->pdev->dev; + u32 rule_entry = 0; + u32 ch, sts; + int err; + + err = reset_control_reset(gpriv->rstc1); + if (err) + return err; + + err = reset_control_reset(gpriv->rstc2); + if (err) + goto fail_reset1; + + /* Enable peripheral clock for register access */ + err = clk_prepare_enable(gpriv->clkp); + if (err) { + dev_err(dev, "failed to enable peripheral clock: %pe\n", + ERR_PTR(err)); + goto fail_reset2; + } + + err = rcar_canfd_reset_controller(gpriv); + if (err) { + dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err)); + goto fail_clk; + } + + /* Controller in Global reset & Channel reset mode */ + rcar_canfd_configure_controller(gpriv); + + /* Configure per channel attributes */ + for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) { + /* Configure Channel's Rx fifo */ + rcar_canfd_configure_rx(gpriv, ch); + + /* Configure Channel's Tx (Common) fifo */ + rcar_canfd_configure_tx(gpriv, ch); + + /* Configure receive rules */ + rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry); + rule_entry += RCANFD_CHANNEL_NUMRULES; + } + + /* Configure common interrupts */ + rcar_canfd_enable_global_interrupts(gpriv); + + /* Start Global operation mode */ + rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK, + RCANFD_GCTR_GMDC_GOPM); + + /* Verify mode change */ + err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, + !(sts & RCANFD_GSTS_GNOPM), 2, 500000); + if (err) { + dev_err(dev, "global operational mode failed\n"); + goto fail_mode; + } + + return 0; + +fail_mode: + rcar_canfd_disable_global_interrupts(gpriv); +fail_clk: + clk_disable_unprepare(gpriv->clkp); +fail_reset2: + reset_control_assert(gpriv->rstc2); +fail_reset1: + reset_control_assert(gpriv->rstc1); + return err; +} + +static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full) +{ + rcar_canfd_disable_global_interrupts(gpriv); + + if (full) { + rcar_canfd_reset_controller(gpriv); + + /* Enter global sleep mode */ + rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR); + } + + clk_disable_unprepare(gpriv->clkp); + reset_control_assert(gpriv->rstc2); + reset_control_assert(gpriv->rstc1); +} + static int rcar_canfd_probe(struct platform_device *pdev) { struct phy *transceivers[RCANFD_NUM_CHANNELS] = { NULL, }; const struct rcar_canfd_hw_info *info; struct device *dev = &pdev->dev; void __iomem *addr; - u32 sts, ch, fcan_freq; struct rcar_canfd_global *gpriv; struct device_node *of_child; unsigned long channels_mask = 0; int err, ch_irq, g_irq; int g_err_irq, g_recc_irq; - u32 rule_entry = 0; bool fdmode = true; /* CAN FD only mode - default */ char name[9] = "channelX"; struct clk *clk_ram; + u32 ch, fcan_freq; int i; info = of_device_get_match_data(dev); @@ -2107,59 +2195,9 @@ static int rcar_canfd_probe(struct platform_device *pdev) } } - err = reset_control_reset(gpriv->rstc1); + err = rcar_canfd_global_init(gpriv); if (err) - goto fail_dev; - err = reset_control_reset(gpriv->rstc2); - if (err) { - reset_control_assert(gpriv->rstc1); - goto fail_dev; - } - - /* Enable peripheral clock for register access */ - err = clk_prepare_enable(gpriv->clkp); - if (err) { - dev_err(dev, "failed to enable peripheral clock: %pe\n", - ERR_PTR(err)); - goto fail_reset; - } - - err = rcar_canfd_reset_controller(gpriv); - if (err) { - dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err)); - goto fail_clk; - } - - /* Controller in Global reset & Channel reset mode */ - rcar_canfd_configure_controller(gpriv); - - /* Configure per channel attributes */ - for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { - /* Configure Channel's Rx fifo */ - rcar_canfd_configure_rx(gpriv, ch); - - /* Configure Channel's Tx (Common) fifo */ - rcar_canfd_configure_tx(gpriv, ch); - - /* Configure receive rules */ - rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry); - rule_entry += RCANFD_CHANNEL_NUMRULES; - } - - /* Configure common interrupts */ - rcar_canfd_enable_global_interrupts(gpriv); - - /* Start Global operation mode */ - rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK, - RCANFD_GCTR_GMDC_GOPM); - - /* Verify mode change */ - err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts, - !(sts & RCANFD_GSTS_GNOPM), 2, 500000); - if (err) { - dev_err(dev, "global operational mode failed\n"); goto fail_mode; - } for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq, @@ -2178,12 +2216,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) rcar_canfd_channel_remove(gpriv, ch); fail_mode: - rcar_canfd_disable_global_interrupts(gpriv); -fail_clk: - clk_disable_unprepare(gpriv->clkp); -fail_reset: - reset_control_assert(gpriv->rstc2); - reset_control_assert(gpriv->rstc1); + rcar_canfd_global_deinit(gpriv, false); fail_dev: return err; } @@ -2198,14 +2231,7 @@ static void rcar_canfd_remove(struct platform_device *pdev) rcar_canfd_channel_remove(gpriv, ch); } - rcar_canfd_disable_global_interrupts(gpriv); - rcar_canfd_reset_controller(gpriv); - - /* Enter global sleep mode */ - rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR); - clk_disable_unprepare(gpriv->clkp); - reset_control_assert(gpriv->rstc2); - reset_control_assert(gpriv->rstc1); + rcar_canfd_global_deinit(gpriv, true); } static int __maybe_unused rcar_canfd_suspend(struct device *dev) -- 2.43.0