Skip to content

Commit ca10989

Browse files
Aisheng Dongmarckleinebudde
authored andcommitted
can: flexcan: implement can Runtime PM
Flexcan will be disabled during suspend if no wakeup function required and enabled after resume accordingly. During this period, we could explicitly disable clocks. Since PM is optional, the clock is enabled at probe to guarante the clock is running when PM is not enabled in the kernel. Implement Runtime PM which will: 1) Without CONFIG_PM, clock is running whether Flexcan up or down. 2) With CONFIG_PM, clock enabled while Flexcan up and disabled when Flexcan down. 3) Disable clock when do system suspend and enable clock while system resume. 4) Make Power Domain framework be able to shutdown the corresponding power domain of this device. Signed-off-by: Aisheng Dong <aisheng.dong@nxp.com> Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent 26bca9f commit ca10989

File tree

1 file changed

+81
-38
lines changed

1 file changed

+81
-38
lines changed

drivers/net/can/flexcan.c

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/of.h>
2525
#include <linux/of_device.h>
2626
#include <linux/platform_device.h>
27+
#include <linux/pm_runtime.h>
2728
#include <linux/regulator/consumer.h>
2829
#include <linux/regmap.h>
2930

@@ -266,6 +267,7 @@ struct flexcan_stop_mode {
266267
struct flexcan_priv {
267268
struct can_priv can;
268269
struct can_rx_offload offload;
270+
struct device *dev;
269271

270272
struct flexcan_regs __iomem *regs;
271273
struct flexcan_mb __iomem *tx_mb;
@@ -444,6 +446,27 @@ static inline void flexcan_error_irq_disable(const struct flexcan_priv *priv)
444446
priv->write(reg_ctrl, &regs->ctrl);
445447
}
446448

449+
static int flexcan_clks_enable(const struct flexcan_priv *priv)
450+
{
451+
int err;
452+
453+
err = clk_prepare_enable(priv->clk_ipg);
454+
if (err)
455+
return err;
456+
457+
err = clk_prepare_enable(priv->clk_per);
458+
if (err)
459+
clk_disable_unprepare(priv->clk_ipg);
460+
461+
return err;
462+
}
463+
464+
static void flexcan_clks_disable(const struct flexcan_priv *priv)
465+
{
466+
clk_disable_unprepare(priv->clk_per);
467+
clk_disable_unprepare(priv->clk_ipg);
468+
}
469+
447470
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
448471
{
449472
if (!priv->reg_xceiver)
@@ -570,19 +593,13 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
570593
const struct flexcan_priv *priv = netdev_priv(dev);
571594
int err;
572595

573-
err = clk_prepare_enable(priv->clk_ipg);
574-
if (err)
596+
err = pm_runtime_get_sync(priv->dev);
597+
if (err < 0)
575598
return err;
576599

577-
err = clk_prepare_enable(priv->clk_per);
578-
if (err)
579-
goto out_disable_ipg;
580-
581600
err = __flexcan_get_berr_counter(dev, bec);
582601

583-
clk_disable_unprepare(priv->clk_per);
584-
out_disable_ipg:
585-
clk_disable_unprepare(priv->clk_ipg);
602+
pm_runtime_put(priv->dev);
586603

587604
return err;
588605
}
@@ -1215,17 +1232,13 @@ static int flexcan_open(struct net_device *dev)
12151232
struct flexcan_priv *priv = netdev_priv(dev);
12161233
int err;
12171234

1218-
err = clk_prepare_enable(priv->clk_ipg);
1219-
if (err)
1235+
err = pm_runtime_get_sync(priv->dev);
1236+
if (err < 0)
12201237
return err;
12211238

1222-
err = clk_prepare_enable(priv->clk_per);
1223-
if (err)
1224-
goto out_disable_ipg;
1225-
12261239
err = open_candev(dev);
12271240
if (err)
1228-
goto out_disable_per;
1241+
goto out_runtime_put;
12291242

12301243
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
12311244
if (err)
@@ -1288,10 +1301,8 @@ static int flexcan_open(struct net_device *dev)
12881301
free_irq(dev->irq, dev);
12891302
out_close:
12901303
close_candev(dev);
1291-
out_disable_per:
1292-
clk_disable_unprepare(priv->clk_per);
1293-
out_disable_ipg:
1294-
clk_disable_unprepare(priv->clk_ipg);
1304+
out_runtime_put:
1305+
pm_runtime_put(priv->dev);
12951306

12961307
return err;
12971308
}
@@ -1306,10 +1317,9 @@ static int flexcan_close(struct net_device *dev)
13061317

13071318
can_rx_offload_del(&priv->offload);
13081319
free_irq(dev->irq, dev);
1309-
clk_disable_unprepare(priv->clk_per);
1310-
clk_disable_unprepare(priv->clk_ipg);
13111320

13121321
close_candev(dev);
1322+
pm_runtime_put(priv->dev);
13131323

13141324
can_led_event(dev, CAN_LED_EVENT_STOP);
13151325

@@ -1349,18 +1359,15 @@ static int register_flexcandev(struct net_device *dev)
13491359
struct flexcan_regs __iomem *regs = priv->regs;
13501360
u32 reg, err;
13511361

1352-
err = clk_prepare_enable(priv->clk_ipg);
1362+
err = flexcan_clks_enable(priv);
13531363
if (err)
13541364
return err;
13551365

1356-
err = clk_prepare_enable(priv->clk_per);
1357-
if (err)
1358-
goto out_disable_ipg;
1359-
13601366
/* select "bus clock", chip must be disabled */
13611367
err = flexcan_chip_disable(priv);
13621368
if (err)
1363-
goto out_disable_per;
1369+
goto out_clks_disable;
1370+
13641371
reg = priv->read(&regs->ctrl);
13651372
reg |= FLEXCAN_CTRL_CLK_SRC;
13661373
priv->write(reg, &regs->ctrl);
@@ -1388,15 +1395,21 @@ static int register_flexcandev(struct net_device *dev)
13881395
}
13891396

13901397
err = register_candev(dev);
1398+
if (err)
1399+
goto out_chip_disable;
13911400

1392-
/* disable core and turn off clocks */
1393-
out_chip_disable:
1401+
/* Disable core and let pm_runtime_put() disable the clocks.
1402+
* If CONFIG_PM is not enabled, the clocks will stay powered.
1403+
*/
13941404
flexcan_chip_disable(priv);
1395-
out_disable_per:
1396-
clk_disable_unprepare(priv->clk_per);
1397-
out_disable_ipg:
1398-
clk_disable_unprepare(priv->clk_ipg);
1405+
pm_runtime_put(priv->dev);
1406+
1407+
return 0;
13991408

1409+
out_chip_disable:
1410+
flexcan_chip_disable(priv);
1411+
out_clks_disable:
1412+
flexcan_clks_disable(priv);
14001413
return err;
14011414
}
14021415

@@ -1556,6 +1569,7 @@ static int flexcan_probe(struct platform_device *pdev)
15561569
priv->write = flexcan_write_le;
15571570
}
15581571

1572+
priv->dev = &pdev->dev;
15591573
priv->can.clock.freq = clock_freq;
15601574
priv->can.bittiming_const = &flexcan_bittiming_const;
15611575
priv->can.do_set_mode = flexcan_set_mode;
@@ -1569,6 +1583,10 @@ static int flexcan_probe(struct platform_device *pdev)
15691583
priv->devtype_data = devtype_data;
15701584
priv->reg_xceiver = reg_xceiver;
15711585

1586+
pm_runtime_get_noresume(&pdev->dev);
1587+
pm_runtime_set_active(&pdev->dev);
1588+
pm_runtime_enable(&pdev->dev);
1589+
15721590
err = register_flexcandev(dev);
15731591
if (err) {
15741592
dev_err(&pdev->dev, "registering netdev failed\n");
@@ -1595,6 +1613,7 @@ static int flexcan_remove(struct platform_device *pdev)
15951613
struct net_device *dev = platform_get_drvdata(pdev);
15961614

15971615
unregister_flexcandev(dev);
1616+
pm_runtime_disable(&pdev->dev);
15981617
free_candev(dev);
15991618

16001619
return 0;
@@ -1604,7 +1623,7 @@ static int __maybe_unused flexcan_suspend(struct device *device)
16041623
{
16051624
struct net_device *dev = dev_get_drvdata(device);
16061625
struct flexcan_priv *priv = netdev_priv(dev);
1607-
int err;
1626+
int err = 0;
16081627

16091628
if (netif_running(dev)) {
16101629
/* if wakeup is enabled, enter stop mode
@@ -1617,20 +1636,22 @@ static int __maybe_unused flexcan_suspend(struct device *device)
16171636
err = flexcan_chip_disable(priv);
16181637
if (err)
16191638
return err;
1639+
1640+
err = pm_runtime_force_suspend(device);
16201641
}
16211642
netif_stop_queue(dev);
16221643
netif_device_detach(dev);
16231644
}
16241645
priv->can.state = CAN_STATE_SLEEPING;
16251646

1626-
return 0;
1647+
return err;
16271648
}
16281649

16291650
static int __maybe_unused flexcan_resume(struct device *device)
16301651
{
16311652
struct net_device *dev = dev_get_drvdata(device);
16321653
struct flexcan_priv *priv = netdev_priv(dev);
1633-
int err;
1654+
int err = 0;
16341655

16351656
priv->can.state = CAN_STATE_ERROR_ACTIVE;
16361657
if (netif_running(dev)) {
@@ -1639,14 +1660,35 @@ static int __maybe_unused flexcan_resume(struct device *device)
16391660
if (device_may_wakeup(device)) {
16401661
disable_irq_wake(dev->irq);
16411662
} else {
1642-
err = flexcan_chip_enable(priv);
1663+
err = pm_runtime_force_resume(device);
16431664
if (err)
16441665
return err;
1666+
1667+
err = flexcan_chip_enable(priv);
16451668
}
16461669
}
1670+
1671+
return err;
1672+
}
1673+
1674+
static int __maybe_unused flexcan_runtime_suspend(struct device *device)
1675+
{
1676+
struct net_device *dev = dev_get_drvdata(device);
1677+
struct flexcan_priv *priv = netdev_priv(dev);
1678+
1679+
flexcan_clks_disable(priv);
1680+
16471681
return 0;
16481682
}
16491683

1684+
static int __maybe_unused flexcan_runtime_resume(struct device *device)
1685+
{
1686+
struct net_device *dev = dev_get_drvdata(device);
1687+
struct flexcan_priv *priv = netdev_priv(dev);
1688+
1689+
return flexcan_clks_enable(priv);
1690+
}
1691+
16501692
static int __maybe_unused flexcan_noirq_suspend(struct device *device)
16511693
{
16521694
struct net_device *dev = dev_get_drvdata(device);
@@ -1673,6 +1715,7 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
16731715

16741716
static const struct dev_pm_ops flexcan_pm_ops = {
16751717
SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume)
1718+
SET_RUNTIME_PM_OPS(flexcan_runtime_suspend, flexcan_runtime_resume, NULL)
16761719
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(flexcan_noirq_suspend, flexcan_noirq_resume)
16771720
};
16781721

0 commit comments

Comments
 (0)