#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
u32 reg_esr;
u32 reg_ctrl_default;
+ struct device *dev;
struct clk *clk_ipg;
struct clk *clk_per;
struct flexcan_platform_data *pdata;
const struct flexcan_priv *priv = netdev_priv(dev);
int err;
- err = flexcan_clks_enable(priv);
- if (err)
- return err;
+ pm_runtime_get_sync(priv->dev);
err = __flexcan_get_berr_counter(dev, bec);
- flexcan_clks_disable(priv);
+ pm_runtime_put(priv->dev);
return err;
}
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr, reg_fdctrl;
int err, i;
- err = flexcan_clks_enable(priv);
- if (err)
- return err;
-
/* enable module */
err = flexcan_chip_enable(priv);
if (err)
- goto out_clocks_disable;
+ return err;
/* soft reset */
err = flexcan_chip_softreset(priv);
flexcan_transceiver_disable(priv);
out_chip_disable:
flexcan_chip_disable(priv);
- out_clocks_disable:
- flexcan_clks_disable(priv);
return err;
}
flexcan_write(priv, FLEXCAN_CTRL, priv->reg_ctrl_default &
~FLEXCAN_CTRL_ERR_ALL);
- flexcan_clks_disable(priv);
-
flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
}
struct flexcan_priv *priv = netdev_priv(dev);
int err;
- err = flexcan_clks_enable(priv);
+ err = pm_runtime_get_sync(priv->dev);
if (err)
return err;
err = open_candev(dev);
if (err)
- goto out_clocks_disable;
+ goto out_pm_runtime;
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
if (err)
out_close:
close_candev(dev);
- out_clocks_disable:
- flexcan_clks_disable(priv);
+ out_pm_runtime:
+ pm_runtime_put(priv->dev);
return err;
}
can_led_event(dev, CAN_LED_EVENT_STOP);
- flexcan_clks_disable(priv);
+ pm_runtime_put(priv->dev);
return 0;
}
struct flexcan_priv *priv = netdev_priv(dev);
u32 reg, err;
- err = flexcan_clks_enable(priv);
- if (err)
- return err;
-
/* select "bus clock", chip must be disabled */
err = flexcan_chip_disable(priv);
if (err)
- goto out_clocks_disable;
+ return err;
+
reg = flexcan_read(priv, FLEXCAN_CTRL);
reg |= FLEXCAN_CTRL_CLK_SRC;
flexcan_write(priv, FLEXCAN_CTRL, reg);
/* disable core and turn off clocks */
out_chip_disable:
flexcan_chip_disable(priv);
- out_clocks_disable:
- flexcan_clks_disable(priv);
return err;
}
dev->flags |= IFF_ECHO;
priv = netdev_priv(dev);
+ priv->dev = &pdev->dev;
priv->can.clock.freq = clock_freq;
priv->can.bittiming_const = &flexcan_bittiming_const;
priv->can.data_bittiming_const = &flexcan_data_bittiming_const;
}
}
+ pm_runtime_enable(&pdev->dev);
+ err = pm_runtime_get_sync(&pdev->dev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get failed(%d)\n", err);
+ goto failed_rpm_disable;
+ }
+
err = register_flexcandev(dev);
if (err) {
dev_err(&pdev->dev, "registering netdev failed\n");
- goto failed_register;
+ goto failed_rpm_put;
}
devm_can_led_init(dev);
device_set_wakeup_capable(&pdev->dev, wakeup);
+ pm_runtime_put(&pdev->dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
priv->base, dev->irq);
return 0;
+ failed_rpm_put:
+ pm_runtime_put(priv->dev);
+ failed_rpm_disable:
+ pm_runtime_disable(&pdev->dev);
failed_register:
free_candev(dev);
+
return err;
}
struct flexcan_priv *priv = netdev_priv(dev);
unregister_flexcandev(dev);
+ pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(dev);
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
+ int ret = 0;
if (netif_running(dev)) {
netif_stop_queue(dev);
flexcan_enter_stop_mode(priv);
} else {
flexcan_chip_stop(dev);
+ ret = pm_runtime_force_suspend(device);
}
}
priv->can.state = CAN_STATE_SLEEPING;
pinctrl_pm_select_sleep_state(device);
- return 0;
+ return ret;
}
static int __maybe_unused flexcan_resume(struct device *device)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(dev)) {
+ err = pm_runtime_force_resume(device);
+ if (err)
+ return err;
+
netif_device_attach(dev);
netif_start_queue(dev);
return err;
}
-static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
+static int __maybe_unused flexcan_runtime_suspend(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+ struct flexcan_priv *priv = netdev_priv(dev);
+
+ flexcan_clks_disable(priv);
+
+ return 0;
+}
+
+static int __maybe_unused flexcan_runtime_resume(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+ struct flexcan_priv *priv = netdev_priv(dev);
+
+ flexcan_clks_enable(priv);
+
+ return 0;
+}
+
+static const struct dev_pm_ops flexcan_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume)
+ SET_RUNTIME_PM_OPS(flexcan_runtime_suspend, flexcan_runtime_resume, NULL)
+};
static struct platform_driver flexcan_driver = {
.driver = {