Merge patch series "can: tcan4x5x/m_can: use standby mode when down and in suspend"

Sean Nyekjaer <sean@geanix.com> says:

When downing the tcan4x5x there is no reason to keep the tcan4x5x in
"normal" mode and waste power. So set standby mode when the interface
is down and normal mode when interface is up.

Also when going into suspend, set the tcan4x5x into standby mode. The
tcan4x5x can still be used as a wake-source when in standby as low
power RX is enabled.

Link: https://patch.msgid.link/20241122-tcan-standby-v3-0-90bafaf5eccd@geanix.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Marc Kleine-Budde
2025-01-10 11:05:46 +01:00
3 changed files with 28 additions and 4 deletions

View File

@@ -1756,6 +1756,13 @@ static void m_can_stop(struct net_device *dev)
/* set the state as STOPPED */
cdev->can.state = CAN_STATE_STOPPED;
if (cdev->ops->deinit) {
ret = cdev->ops->deinit(cdev);
if (ret)
netdev_err(dev, "failed to deinitialize: %pe\n",
ERR_PTR(ret));
}
}
static int m_can_close(struct net_device *dev)
@@ -2437,6 +2444,7 @@ int m_can_class_suspend(struct device *dev)
{
struct m_can_classdev *cdev = dev_get_drvdata(dev);
struct net_device *ndev = cdev->net;
int ret = 0;
if (netif_running(ndev)) {
netif_stop_queue(ndev);
@@ -2449,6 +2457,9 @@ int m_can_class_suspend(struct device *dev)
if (cdev->pm_wake_source) {
hrtimer_cancel(&cdev->hrtimer);
m_can_write(cdev, M_CAN_IE, IR_RF0N);
if (cdev->ops->deinit)
ret = cdev->ops->deinit(cdev);
} else {
m_can_stop(ndev);
}
@@ -2460,7 +2471,7 @@ int m_can_class_suspend(struct device *dev)
cdev->can.state = CAN_STATE_SLEEPING;
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(m_can_class_suspend);
@@ -2468,14 +2479,13 @@ int m_can_class_resume(struct device *dev)
{
struct m_can_classdev *cdev = dev_get_drvdata(dev);
struct net_device *ndev = cdev->net;
int ret = 0;
pinctrl_pm_select_default_state(dev);
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
int ret;
ret = m_can_clk_start(cdev);
if (ret)
return ret;
@@ -2488,6 +2498,10 @@ int m_can_class_resume(struct device *dev)
* again.
*/
cdev->active_interrupts |= IR_RF0N | IR_TEFN;
if (cdev->ops->init)
ret = cdev->ops->init(cdev);
m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
} else {
ret = m_can_start(ndev);
@@ -2501,7 +2515,7 @@ int m_can_class_resume(struct device *dev)
netif_start_queue(ndev);
}
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(m_can_class_resume);

View File

@@ -68,6 +68,7 @@ struct m_can_ops {
int (*write_fifo)(struct m_can_classdev *cdev, int addr_offset,
const void *val, size_t val_count);
int (*init)(struct m_can_classdev *cdev);
int (*deinit)(struct m_can_classdev *cdev);
};
struct m_can_tx_op {

View File

@@ -279,6 +279,14 @@ static int tcan4x5x_init(struct m_can_classdev *cdev)
return ret;
}
static int tcan4x5x_deinit(struct m_can_classdev *cdev)
{
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_STANDBY);
};
static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
{
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
@@ -376,6 +384,7 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
static const struct m_can_ops tcan4x5x_ops = {
.init = tcan4x5x_init,
.deinit = tcan4x5x_deinit,
.read_reg = tcan4x5x_read_reg,
.write_reg = tcan4x5x_write_reg,
.write_fifo = tcan4x5x_write_fifo,