am62 requires a wakeup flag being set in pinctrl when mcan pins acts as
a wakeup source. Add support to select the wakeup state if WOL is
enabled.
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
---
drivers/net/can/m_can/m_can.c | 69 +++++++++++++++++++++++++++++++++++++++++--
drivers/net/can/m_can/m_can.h | 3 ++
2 files changed, 70 insertions(+), 2 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index e08fae5ddf5efa8345670dd50d50954ec5d52b29..a1fa4b2f6b6cc94e5e10259cca53bd931ab238c8 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -2249,7 +2249,26 @@ static int m_can_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return ret;
}
+ if (!IS_ERR_OR_NULL(cdev->pinctrl_state_wakeup)) {
+ if (wol_enable)
+ ret = pinctrl_select_state(cdev->pinctrl, cdev->pinctrl_state_wakeup);
+ else
+ ret = pinctrl_pm_select_default_state(cdev->dev);
+
+ if (ret) {
+ netdev_err(cdev->net, "Failed to select pinctrl state %pE\n",
+ ERR_PTR(ret));
+ goto err_wakeup_enable;
+ }
+ }
+
return 0;
+
+err_wakeup_enable:
+ /* Revert wakeup enable */
+ device_set_wakeup_enable(cdev->dev, !wol_enable);
+
+ return ret;
}
static const struct ethtool_ops m_can_ethtool_ops_coalescing = {
@@ -2377,6 +2396,42 @@ int m_can_class_get_clocks(struct m_can_classdev *cdev)
}
EXPORT_SYMBOL_GPL(m_can_class_get_clocks);
+static bool m_can_class_wakeup_pinctrl_enabled(struct m_can_classdev *class_dev)
+{
+ return device_may_wakeup(class_dev->dev) && class_dev->pinctrl_state_wakeup;
+}
+
+static int m_can_class_setup_optional_pinctrl(struct m_can_classdev *class_dev)
+{
+ struct device *dev = class_dev->dev;
+ int ret;
+
+ class_dev->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(class_dev->pinctrl)) {
+ ret = PTR_ERR(class_dev->pinctrl);
+ class_dev->pinctrl = NULL;
+
+ if (ret == -ENODEV)
+ return 0;
+
+ return dev_err_probe(dev, ret, "Failed to get pinctrl\n");
+ }
+
+ class_dev->pinctrl_state_wakeup =
+ pinctrl_lookup_state(class_dev->pinctrl, "wakeup");
+ if (IS_ERR(class_dev->pinctrl_state_wakeup)) {
+ ret = PTR_ERR(class_dev->pinctrl_state_wakeup);
+ class_dev->pinctrl_state_wakeup = NULL;
+
+ if (ret == -ENODEV)
+ return 0;
+
+ return dev_err_probe(dev, ret, "Failed to lookup pinctrl wakeup state\n");
+ }
+
+ return 0;
+}
+
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev,
int sizeof_priv)
{
@@ -2418,7 +2473,15 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev,
m_can_of_parse_mram(class_dev, mram_config_vals);
spin_lock_init(&class_dev->tx_handling_spinlock);
+ ret = m_can_class_setup_optional_pinctrl(class_dev);
+ if (ret)
+ goto err_free_candev;
+
return class_dev;
+
+err_free_candev:
+ free_candev(net_dev);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
@@ -2533,7 +2596,8 @@ int m_can_class_suspend(struct device *dev)
m_can_clk_stop(cdev);
}
- pinctrl_pm_select_sleep_state(dev);
+ if (!m_can_class_wakeup_pinctrl_enabled(cdev))
+ pinctrl_pm_select_sleep_state(dev);
cdev->can.state = CAN_STATE_SLEEPING;
@@ -2547,7 +2611,8 @@ int m_can_class_resume(struct device *dev)
struct net_device *ndev = cdev->net;
int ret = 0;
- pinctrl_pm_select_default_state(dev);
+ if (!m_can_class_wakeup_pinctrl_enabled(cdev))
+ pinctrl_pm_select_default_state(dev);
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index bd4746c63af3f0a032910644dfd48a9ebb3a6168..583c7f1d005d61b3fc8587697388522993ff11a8 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -128,6 +128,9 @@ struct m_can_classdev {
struct mram_cfg mcfg[MRAM_CFG_NUM];
struct hrtimer hrtimer;
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_state_wakeup;
};
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
--
2.50.1
On Aug 20, 2025 at 14:42:28 +0200, Markus Schneider-Pargmann wrote: > am62 requires a wakeup flag being set in pinctrl when mcan pins acts as Let's call it "TI AM62x SoC" or TI K3 SoCs? This commit goes into a driver so let's not assume everyone knows what am62 means ;) Also nit: s/"mcan pins acts"/"mcan pins act"/ > a wakeup source. Add support to select the wakeup state if WOL is > enabled. > > Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com> > --- > drivers/net/can/m_can/m_can.c | 69 +++++++++++++++++++++++++++++++++++++++++-- > drivers/net/can/m_can/m_can.h | 3 ++ > 2 files changed, 70 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c > index e08fae5ddf5efa8345670dd50d50954ec5d52b29..a1fa4b2f6b6cc94e5e10259cca53bd931ab238c8 100644 > --- a/drivers/net/can/m_can/m_can.c > +++ b/drivers/net/can/m_can/m_can.c > @@ -2249,7 +2249,26 @@ static int m_can_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) > return ret; > } > > + if (!IS_ERR_OR_NULL(cdev->pinctrl_state_wakeup)) { > + if (wol_enable) > + ret = pinctrl_select_state(cdev->pinctrl, cdev->pinctrl_state_wakeup); > + else > + ret = pinctrl_pm_select_default_state(cdev->dev); > + > + if (ret) { > + netdev_err(cdev->net, "Failed to select pinctrl state %pE\n", > + ERR_PTR(ret)); > + goto err_wakeup_enable; > + } > + } > + > return 0; > + > +err_wakeup_enable: > + /* Revert wakeup enable */ > + device_set_wakeup_enable(cdev->dev, !wol_enable); > + > + return ret; > } > > static const struct ethtool_ops m_can_ethtool_ops_coalescing = { > @@ -2377,6 +2396,42 @@ int m_can_class_get_clocks(struct m_can_classdev *cdev) > } > EXPORT_SYMBOL_GPL(m_can_class_get_clocks); > > +static bool m_can_class_wakeup_pinctrl_enabled(struct m_can_classdev *class_dev) > +{ > + return device_may_wakeup(class_dev->dev) && class_dev->pinctrl_state_wakeup; > +} > + > +static int m_can_class_setup_optional_pinctrl(struct m_can_classdev *class_dev) > +{ > + struct device *dev = class_dev->dev; > + int ret; > + > + class_dev->pinctrl = devm_pinctrl_get(dev); > + if (IS_ERR(class_dev->pinctrl)) { > + ret = PTR_ERR(class_dev->pinctrl); > + class_dev->pinctrl = NULL; > + > + if (ret == -ENODEV) > + return 0; > + > + return dev_err_probe(dev, ret, "Failed to get pinctrl\n"); > + } > + > + class_dev->pinctrl_state_wakeup = > + pinctrl_lookup_state(class_dev->pinctrl, "wakeup"); > + if (IS_ERR(class_dev->pinctrl_state_wakeup)) { > + ret = PTR_ERR(class_dev->pinctrl_state_wakeup); > + class_dev->pinctrl_state_wakeup = NULL; > + > + if (ret == -ENODEV) > + return 0; > + > + return dev_err_probe(dev, ret, "Failed to lookup pinctrl wakeup state\n"); > + } > + > + return 0; > +} > + > struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, > int sizeof_priv) > { > @@ -2418,7 +2473,15 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, > m_can_of_parse_mram(class_dev, mram_config_vals); > spin_lock_init(&class_dev->tx_handling_spinlock); > > + ret = m_can_class_setup_optional_pinctrl(class_dev); optional makes it sound a little confusing IMO, might make sense to call it something like m_can_class_configure_pinctrl or m_can_class_setup_wakeup_pinctrl > + if (ret) > + goto err_free_candev; > + > return class_dev; > + > +err_free_candev: > + free_candev(net_dev); > + return ERR_PTR(ret); > } > EXPORT_SYMBOL_GPL(m_can_class_allocate_dev); > > @@ -2533,7 +2596,8 @@ int m_can_class_suspend(struct device *dev) > m_can_clk_stop(cdev); > } > > - pinctrl_pm_select_sleep_state(dev); > + if (!m_can_class_wakeup_pinctrl_enabled(cdev)) > + pinctrl_pm_select_sleep_state(dev); > > cdev->can.state = CAN_STATE_SLEEPING; > > @@ -2547,7 +2611,8 @@ int m_can_class_resume(struct device *dev) > struct net_device *ndev = cdev->net; > int ret = 0; > > - pinctrl_pm_select_default_state(dev); > + if (!m_can_class_wakeup_pinctrl_enabled(cdev)) > + pinctrl_pm_select_default_state(dev); > > cdev->can.state = CAN_STATE_ERROR_ACTIVE; > > diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h > index bd4746c63af3f0a032910644dfd48a9ebb3a6168..583c7f1d005d61b3fc8587697388522993ff11a8 100644 > --- a/drivers/net/can/m_can/m_can.h > +++ b/drivers/net/can/m_can/m_can.h > @@ -128,6 +128,9 @@ struct m_can_classdev { > struct mram_cfg mcfg[MRAM_CFG_NUM]; > > struct hrtimer hrtimer; > + > + struct pinctrl *pinctrl; > + struct pinctrl_state *pinctrl_state_wakeup; > }; > > struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv); > > -- > 2.50.1 > -- Best regards, Dhruva Gole Texas Instruments Incorporated
On 9/4/25 04:05, Dhruva Gole wrote: > On Aug 20, 2025 at 14:42:28 +0200, Markus Schneider-Pargmann wrote: >> am62 requires a wakeup flag being set in pinctrl when mcan pins acts as > > Let's call it "TI AM62x SoC" or TI K3 SoCs? This commit goes into a driver so let's not assume > everyone knows what am62 means ;) > > Also nit: s/"mcan pins acts"/"mcan pins act"/ > >> a wakeup source. Add support to select the wakeup state if WOL is >> enabled. >> >> Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com> >> --- >> drivers/net/can/m_can/m_can.c | 69 +++++++++++++++++++++++++++++++++++++++++-- >> drivers/net/can/m_can/m_can.h | 3 ++ >> 2 files changed, 70 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c >> index e08fae5ddf5efa8345670dd50d50954ec5d52b29..a1fa4b2f6b6cc94e5e10259cca53bd931ab238c8 100644 >> --- a/drivers/net/can/m_can/m_can.c >> +++ b/drivers/net/can/m_can/m_can.c >> @@ -2249,7 +2249,26 @@ static int m_can_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) >> return ret; >> } >> >> + if (!IS_ERR_OR_NULL(cdev->pinctrl_state_wakeup)) { >> + if (wol_enable) >> + ret = pinctrl_select_state(cdev->pinctrl, cdev->pinctrl_state_wakeup); >> + else >> + ret = pinctrl_pm_select_default_state(cdev->dev); >> + >> + if (ret) { >> + netdev_err(cdev->net, "Failed to select pinctrl state %pE\n", >> + ERR_PTR(ret)); >> + goto err_wakeup_enable; >> + } >> + } >> + >> return 0; >> + >> +err_wakeup_enable: >> + /* Revert wakeup enable */ >> + device_set_wakeup_enable(cdev->dev, !wol_enable); >> + >> + return ret; >> } >> >> static const struct ethtool_ops m_can_ethtool_ops_coalescing = { >> @@ -2377,6 +2396,42 @@ int m_can_class_get_clocks(struct m_can_classdev *cdev) >> } >> EXPORT_SYMBOL_GPL(m_can_class_get_clocks); >> >> +static bool m_can_class_wakeup_pinctrl_enabled(struct m_can_classdev *class_dev) >> +{ >> + return device_may_wakeup(class_dev->dev) && class_dev->pinctrl_state_wakeup; >> +} >> + >> +static int m_can_class_setup_optional_pinctrl(struct m_can_classdev *class_dev) >> +{ >> + struct device *dev = class_dev->dev; >> + int ret; >> + >> + class_dev->pinctrl = devm_pinctrl_get(dev); >> + if (IS_ERR(class_dev->pinctrl)) { >> + ret = PTR_ERR(class_dev->pinctrl); >> + class_dev->pinctrl = NULL; >> + >> + if (ret == -ENODEV) >> + return 0; >> + >> + return dev_err_probe(dev, ret, "Failed to get pinctrl\n"); >> + } >> + >> + class_dev->pinctrl_state_wakeup = >> + pinctrl_lookup_state(class_dev->pinctrl, "wakeup"); >> + if (IS_ERR(class_dev->pinctrl_state_wakeup)) { >> + ret = PTR_ERR(class_dev->pinctrl_state_wakeup); >> + class_dev->pinctrl_state_wakeup = NULL; >> + >> + if (ret == -ENODEV) >> + return 0; >> + >> + return dev_err_probe(dev, ret, "Failed to lookup pinctrl wakeup state\n"); >> + } >> + >> + return 0; >> +} >> + >> struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, >> int sizeof_priv) >> { >> @@ -2418,7 +2473,15 @@ struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, >> m_can_of_parse_mram(class_dev, mram_config_vals); >> spin_lock_init(&class_dev->tx_handling_spinlock); >> >> + ret = m_can_class_setup_optional_pinctrl(class_dev); > > optional makes it sound a little confusing IMO, might make sense to call > it something like m_can_class_configure_pinctrl or m_can_class_setup_wakeup_pinctrl I agree it should be changed to something different. Maybe you could add a comment or add in the commit message denoting that configuring the pinctrl is optional? > >> + if (ret) >> + goto err_free_candev; >> + >> return class_dev; >> + >> +err_free_candev: >> + free_candev(net_dev); >> + return ERR_PTR(ret); >> } >> EXPORT_SYMBOL_GPL(m_can_class_allocate_dev); >> >> @@ -2533,7 +2596,8 @@ int m_can_class_suspend(struct device *dev) >> m_can_clk_stop(cdev); >> } >> >> - pinctrl_pm_select_sleep_state(dev); >> + if (!m_can_class_wakeup_pinctrl_enabled(cdev)) >> + pinctrl_pm_select_sleep_state(dev); >> >> cdev->can.state = CAN_STATE_SLEEPING; >> >> @@ -2547,7 +2611,8 @@ int m_can_class_resume(struct device *dev) >> struct net_device *ndev = cdev->net; >> int ret = 0; >> >> - pinctrl_pm_select_default_state(dev); >> + if (!m_can_class_wakeup_pinctrl_enabled(cdev)) >> + pinctrl_pm_select_default_state(dev); >> >> cdev->can.state = CAN_STATE_ERROR_ACTIVE; >> >> diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h >> index bd4746c63af3f0a032910644dfd48a9ebb3a6168..583c7f1d005d61b3fc8587697388522993ff11a8 100644 >> --- a/drivers/net/can/m_can/m_can.h >> +++ b/drivers/net/can/m_can/m_can.h >> @@ -128,6 +128,9 @@ struct m_can_classdev { >> struct mram_cfg mcfg[MRAM_CFG_NUM]; >> >> struct hrtimer hrtimer; >> + >> + struct pinctrl *pinctrl; >> + struct pinctrl_state *pinctrl_state_wakeup; >> }; >> >> struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv); >> >> -- >> 2.50.1 >> >
© 2016 - 2025 Red Hat, Inc.