On 11/27/19 6:56 AM, Joakim Zhang wrote: > CAN controller could be stucked in stop mode once it enters stop mode ^^^^^^^ stuck > when suspend, and then it fails to exit stop mode when resume. How can this happen? > Only code reset can get CAN out of stop mode, What is "code reset"? > so add stop mode remove request during probe stage for other > methods(soft reset from chip level, unbind/bind driver, etc) to let ^^^ please add a space > CAN active again. Can you rephrase the sentence after "so add stop mode remove request during probe stage". I'm not completely sure what you want to tell. > MCR[LPMACK] will be checked when enable CAN in > register_flexcandev(). > > Suggested-by: Sean Nyekjaer > Signed-off-by: Joakim Zhang > ------ > ChangeLog: > V1->V2: new add. > --- > drivers/net/can/flexcan.c | 28 ++++++++++++++++++++++------ > 1 file changed, 22 insertions(+), 6 deletions(-) > > diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c > index 2297663cacb2..5d5ed28d3005 100644 > --- a/drivers/net/can/flexcan.c > +++ b/drivers/net/can/flexcan.c > @@ -449,6 +449,13 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) > return 0; > } > > +static void flexcan_try_exit_stop_mode(struct flexcan_priv *priv) > +{ > + /* remove stop request */ > + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, > + 1 << priv->stm.req_bit, 0); > +} > + > static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) > { > struct flexcan_regs __iomem *regs = priv->regs; > @@ -1649,6 +1656,21 @@ static int flexcan_probe(struct platform_device *pdev) > priv->devtype_data = devtype_data; > priv->reg_xceiver = reg_xceiver; > > + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) { > + err = flexcan_setup_stop_mode(pdev); > + if (err) > + dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); > + > + /* CAN controller could be stucked in stop mode once it enters > + * stop mode when suspend, and then it fails to exit stop > + * mode when resume. Only code reset can get CAN out of stop > + * mode, so add stop mode remove request here for other methods > + * (soft reset, bind, etc) to let CAN active again. MCR[LPMACK] > + * will be checked when enable CAN in register_flexcandev(). > + */ > + flexcan_try_exit_stop_mode(priv); > + } > + > pm_runtime_get_noresume(&pdev->dev); > pm_runtime_set_active(&pdev->dev); > pm_runtime_enable(&pdev->dev); > @@ -1661,12 +1683,6 @@ static int flexcan_probe(struct platform_device *pdev) > > devm_can_led_init(dev); > > - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) { > - err = flexcan_setup_stop_mode(pdev); > - if (err) > - dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); > - } > - > return 0; > > failed_register: > Marc -- Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung West/Dortmund | Phone: +49-231-2826-924 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |