-
Notifications
You must be signed in to change notification settings - Fork 8.3k
drivers: can: mcp251xfd: Add support for sleep mode #100520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add support for MCP251xFD sleep mode using device power management. When in sleep mode, controller will wake automatically on CAN activity via WAKIF. Enter sleep mode by calling: pm_device_action_run(can_dev, PM_DEVICE_ACTION_SUSPEND); Leave sleep mode by calling: pm_device_action_run(can_dev, PM_DEVICE_ACTION_RESUME); Add config options to enable power management support as well as an option to enable management of transceiver standby automatically when sleep mode is entered. Signed-off-by: Tomas Ridl <[email protected]>
|
Hello @tomridl, and thank you very much for your first pull request to the Zephyr project! |
henrikbrixandersen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks you for submitting this. A few initial comments below:
drivers/can/Kconfig.mcp251xfd
Outdated
| config CAN_MCP251XFD_PM_DEVICE | ||
| bool "Enable power management support" | ||
| default n | ||
| depends on PM_DEVICE | ||
| help | ||
| Enable power management support for the MCP251XFD CAN controller. | ||
| When enabled, the driver implements suspend and resume callbacks | ||
| that transition the device to sleep mode on suspend and restore | ||
| the previous operational mode on resume. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be a dedicated, driver-specific Kconfig. Enabling CONFIG_PM_DEVICE should be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do - the reason for the extra config was that entering sleep mode could cause CAN packets to be missed on wakeup, so devices that implement CONFIG_PM for other reasons could optionally prevent the CAN controller going to sleep if it is critical to receive every CAN packet. Could an option perhaps be added to the dts instead?
Edit: Doh, if they don't want to use sleep mode then just don't call pm_device_action_run(can_dev, PM_DEVICE_ACTION_SUSPEND);
drivers/can/can_mcp251xfd.c
Outdated
| if (requested_mode == MCP251XFD_REG_CON_MODE_CAN2_0 || | ||
| requested_mode == MCP251XFD_REG_CON_MODE_EXT_LOOPBACK || | ||
| if (requested_mode == MCP251XFD_REG_CON_MODE_CAN2_0 || | ||
| requested_mode == MCP251XFD_REG_CON_MODE_EXT_LOOPBACK || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not mix unrelated whitespace changes with functional changes. Same goes for the rest of the file.
drivers/can/can_mcp251xfd.c
Outdated
| @@ -1099,6 +1111,24 @@ static void mcp251xfd_handle_interrupts(const struct device *dev) | |||
| } | |||
| } | |||
|
|
|||
| #if defined(CONFIG_CAN_MCP251XFD_PM_DEVICE) | |||
| if ((reg_int & MCP251XFD_REG_INT_WAKIF) != 0) { | |||
| LOG_INF("WAKIF Interrupt - CAN bus activity wake"); | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reduce the log level here to DBG.
drivers/can/can_mcp251xfd.c
Outdated
| /* If in operational mode (NORMAL/LISTENONLY), first abort any pending TX | ||
| * and transition to CONFIG mode for clean sleep entry. | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please invert this to disallow entering sleep mode while in operational mode (see discussion in #96039 for details).
Will the MCP251xFD retain CAN RX filter configuration while in sleep mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the MCP251xFD retains CAN RX filter configuration while in sleep mode (the same is not true for LP mode, however LP mode has not been implemented here.
According to the MCP25XXFD family reference manual, sleep mode can be entered from normal mode however in testing I found it more reliable to switch to config mode first. I will change this to match the implementation for tcan4x5x and only allow entry from configuration mode.
| @@ -1688,6 +1721,274 @@ static int mcp251xfd_init(const struct device *dev) | |||
| return ret; | |||
| } | |||
|
|
|||
| #if defined(CONFIG_CAN_MCP251XFD_PM_DEVICE) | |||
| static int mcp251xfd_enter_sleep_mode(const struct device *dev) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is very long and complicated. Please consider refactoring it for readability.
drivers/can/can_mcp251xfd.c
Outdated
| ret = mcp251xfd_reg_check_value_wtimeout( | ||
| dev, MCP251XFD_REG_CON, | ||
| FIELD_PREP(MCP251XFD_REG_CON_OPMOD_MASK, MCP251XFD_REG_CON_MODE_CONFIG), | ||
| MCP251XFD_REG_CON_OPMOD_MASK, MCP251XFD_MODE_CHANGE_TIMEOUT_USEC, | ||
| MCP251XFD_MODE_CHANGE_RETRIES, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid formatting like this (Python-like) where a function call ends with ( on a line. Put the arguments on the same line up to 100 characters in width.
drivers/can/can_mcp251xfd.c
Outdated
| #if defined(CONFIG_CAN_MCP251XFD_TRANSCEIVER_STANDBY_ON_SLEEP) | ||
| if (dev_cfg->common.phy != NULL) { | ||
| /* Put transceiver in standby for lowest power */ | ||
| (void)can_transceiver_disable(dev_cfg->common.phy); | ||
| } | ||
| #endif | ||
| } | ||
| break; | ||
|
|
||
| case PM_DEVICE_ACTION_RESUME: | ||
| LOG_DBG("PM resume requested"); | ||
|
|
||
| #if defined(CONFIG_CAN_MCP251XFD_TRANSCEIVER_STANDBY_ON_SLEEP) | ||
| if (dev_cfg->common.phy != NULL) { | ||
| /* Bring transceiver out of standby */ | ||
| (void)can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); | ||
| } | ||
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suspending/disabling the CAN transceiver due to PM is the task of the CAN transceiver driver (not the individual CAN controller driver), which needs to implement device PM by itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the existing mcp251xfd_stop and mcp251xfd_start functions already control the transceiver standby, so switching to configuration mode using can_stop (putting the device in configuration mode) will already put the transceiver to sleep. I will switch the PM_DEVICE_ACTION_RESUME to use mcp251xfd_start which will then switch the transceiver out of standby.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the CAN controller will be in stopped mode when entering sleep mode, resuming should not put it into started mode - that's up to the application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it - will restore to config mode after wake from sleep and leave it up to the app to start.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although then I'm not sure how to restart the controller when waking from CAN activity - the state_changed_callback doesn't have a defined state for WAKIF so how should this be handled?
Add support for MCP251xFD sleep mode using device power management. When in sleep mode, controller will wake automatically on CAN activity via WAKIF. Enter sleep mode by calling: pm_device_action_run(can_dev, PM_DEVICE_ACTION_SUSPEND); Leave sleep mode by calling: pm_device_action_run(can_dev, PM_DEVICE_ACTION_RESUME); Signed-off-by: Tomas Ridl <[email protected]>
Remove transceiver interactions from PM handler. Signed-off-by: Tomas Ridl <[email protected]>
Removed unused variable. Signed-off-by: Tomas Ridl <[email protected]>
Removed unused variable dev_cfg. Signed-off-by: Tomas Ridl <[email protected]>
|



Add support for MCP251xFD sleep mode using device power management. When in sleep mode, controller will wake automatically on CAN activity via WAKIF.
Sleep mode is entered by calling
pm_device_action_run(can_dev, PM_DEVICE_ACTION_SUSPEND);Sleep mode can be exited by calling
pm_device_action_run(can_dev, PM_DEVICE_ACTION_RESUME);Add config options to enable power management support as well as an option to enable management of transceiver standby automatically when sleep mode is entered.