mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
can: flexcan: add auto stop mode for IMX93 to support wakeup
IMX93 do not contain a GPR to config the stop mode, it will set the flexcan into stop mode automatically once the ARM core go into low power mode (WFI instruct) and gate off the flexcan related clock automatically. But to let these logic work as expect, before ARM core go into low power mode, need to make sure the flexcan related clock keep on. To support stop mode and wakeup feature on imx93, this patch add a new fsl_imx93_devtype_data to separate from imx8mp. Signed-off-by: Haibo Chen <haibo.chen@nxp.com> Link: https://lore.kernel.org/all/1669116752-4260-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
parent
8fd9323ef7
commit
8cb53b485f
@ -345,6 +345,15 @@ static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static struct flexcan_devtype_data fsl_imx93_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_AUTO_STOP_MODE |
|
||||
FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
@ -532,9 +541,14 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
|
||||
ret = flexcan_stop_mode_enable_scfw(priv, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
} else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
|
||||
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
|
||||
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
|
||||
} else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE) {
|
||||
/* For the auto stop mode, software do nothing, hardware will cover
|
||||
* all the operation automatically after system go into low power mode.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flexcan_low_power_enter_ack(priv);
|
||||
@ -551,7 +565,7 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
|
||||
ret = flexcan_stop_mode_enable_scfw(priv, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
} else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
|
||||
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
|
||||
1 << priv->stm.req_bit, 0);
|
||||
}
|
||||
@ -560,6 +574,12 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
|
||||
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
|
||||
priv->write(reg_mcr, ®s->mcr);
|
||||
|
||||
/* For the auto stop mode, hardware will exist stop mode
|
||||
* automatically after system go out of low power mode.
|
||||
*/
|
||||
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
|
||||
return 0;
|
||||
|
||||
return flexcan_low_power_exit_ack(priv);
|
||||
}
|
||||
|
||||
@ -1974,6 +1994,8 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
|
||||
ret = flexcan_setup_stop_mode_scfw(pdev);
|
||||
else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR)
|
||||
ret = flexcan_setup_stop_mode_gpr(pdev);
|
||||
else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
|
||||
ret = 0;
|
||||
else
|
||||
/* return 0 directly if doesn't support stop mode feature */
|
||||
return 0;
|
||||
@ -1992,6 +2014,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
|
||||
static const struct of_device_id flexcan_of_match[] = {
|
||||
{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
|
||||
{ .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
|
||||
{ .compatible = "fsl,imx93-flexcan", .data = &fsl_imx93_devtype_data, },
|
||||
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
|
||||
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
|
||||
{ .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
|
||||
@ -2299,8 +2322,16 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device)
|
||||
if (netif_running(dev)) {
|
||||
int err;
|
||||
|
||||
if (device_may_wakeup(device))
|
||||
if (device_may_wakeup(device)) {
|
||||
flexcan_enable_wakeup_irq(priv, true);
|
||||
/* For auto stop mode, need to keep the clock on before
|
||||
* system go into low power mode. After system go into
|
||||
* low power mode, hardware will config the flexcan into
|
||||
* stop mode, and gate off the clock automatically.
|
||||
*/
|
||||
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_AUTO_STOP_MODE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = pm_runtime_force_suspend(device);
|
||||
if (err)
|
||||
|
@ -68,6 +68,8 @@
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15)
|
||||
/* Device supports RX via FIFO */
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16)
|
||||
/* auto enter stop mode to support wakeup */
|
||||
#define FLEXCAN_QUIRK_AUTO_STOP_MODE BIT(17)
|
||||
|
||||
struct flexcan_devtype_data {
|
||||
u32 quirks; /* quirks needed for different IP cores */
|
||||
|
Loading…
Reference in New Issue
Block a user