free_irq(ndev->irq, ndev);
close_candev(ndev);
+ pm_runtime_put(priv->dev);
+
return 0;
}
struct ipms_canfd_priv *priv = netdev_priv(ndev);
int ret;
+ ret = pm_runtime_get_sync(priv->dev);
+ if (ret < 0) {
+ dev_err(priv->dev, " %s: pm_runtime_get failed\n", __func__);
+ goto err;
+ }
+
/* Set chip into reset mode */
ret = set_reset_mode(ndev);
if (ret) {
exit_can_start:
free_irq(ndev->irq, ndev);
+err:
+ pm_runtime_put(priv->dev);
exit_irq:
close_candev(ndev);
return ret;
priv->reg_base = addr;
priv->write_reg = canfd_write_reg_le;
priv->read_reg = canfd_read_reg_le;
+
+ pm_runtime_enable(&pdev->dev);
+
priv->can_clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(priv->can_clk)) {
dev_err(&pdev->dev, "Device clock not found.\n");
reset_control_assert(priv->resets);
clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
+ pm_runtime_disable(&pdev->dev);
unregister_candev(ndev);
netif_napi_del(&priv->napi);
return 0;
}
+#ifdef CONFIG_PM
+static int canfd_runtime_suspend(struct device *dev)
+{
+ struct ipms_canfd_priv *priv = dev_get_drvdata(dev);
+
+ reset_control_assert(priv->resets);
+ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
+
+ return 0;
+}
+
+static int canfd_runtime_resume(struct device *dev)
+{
+ struct ipms_canfd_priv *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
+ if (ret) {
+ dev_err(dev, "Failed to prepare_enable clk\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(priv->resets);
+ if (ret) {
+ dev_err(dev, "Failed to deassert reset\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(canfd_pm_ops, canfd_runtime_suspend,
+ canfd_runtime_resume, NULL);
+
static const struct of_device_id canfd_of_match[] = {
{ .compatible = "ipms,can" },
{ }
.remove = canfd_driver_remove,
.driver = {
.name = DRIVER_NAME,
+ .pm = &canfd_pm_ops,
.of_match_table = canfd_of_match,
},
};