#include <linux/io.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/coresight.h>
/**
* struct replicator_drvdata - specifics associated to a replicator component
* @dev: the device entity associated with this component
+ * @atclk: optional clock for the core parts of the replicator.
* @csdev: component vitals needed by the framework
*/
struct replicator_drvdata {
struct device *dev;
+ struct clk *atclk;
struct coresight_device *csdev;
};
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ pm_runtime_get_sync(drvdata->dev);
dev_info(drvdata->dev, "REPLICATOR enabled\n");
return 0;
}
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ pm_runtime_put(drvdata->dev);
dev_info(drvdata->dev, "REPLICATOR disabled\n");
}
static int replicator_probe(struct platform_device *pdev)
{
+ int ret;
struct device *dev = &pdev->dev;
struct coresight_platform_data *pdata = NULL;
struct replicator_drvdata *drvdata;
return -ENOMEM;
drvdata->dev = &pdev->dev;
+ drvdata->atclk = devm_clk_get(&pdev->dev, "atclk"); /* optional */
+ if (!IS_ERR(drvdata->atclk)) {
+ ret = clk_prepare_enable(drvdata->atclk);
+ if (ret)
+ return ret;
+ }
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
platform_set_drvdata(pdev, drvdata);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
+ if (!desc) {
+ ret = -ENOMEM;
+ goto out_disable_pm;
+ }
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc->pdata = pdev->dev.platform_data;
desc->dev = &pdev->dev;
drvdata->csdev = coresight_register(desc);
- if (IS_ERR(drvdata->csdev))
- return PTR_ERR(drvdata->csdev);
+ if (IS_ERR(drvdata->csdev)) {
+ ret = PTR_ERR(drvdata->csdev);
+ goto out_disable_pm;
+ }
+
+ pm_runtime_put(&pdev->dev);
dev_info(dev, "REPLICATOR initialized\n");
return 0;
+
+out_disable_pm:
+ if (!IS_ERR(drvdata->atclk))
+ clk_disable_unprepare(drvdata->atclk);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
}
static int replicator_remove(struct platform_device *pdev)
struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
coresight_unregister(drvdata->csdev);
+ pm_runtime_get_sync(&pdev->dev);
+ if (!IS_ERR(drvdata->atclk))
+ clk_disable_unprepare(drvdata->atclk);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int replicator_runtime_suspend(struct device *dev)
+{
+ struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (drvdata && !IS_ERR(drvdata->atclk))
+ clk_disable_unprepare(drvdata->atclk);
+
return 0;
}
+static int replicator_runtime_resume(struct device *dev)
+{
+ struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (drvdata && !IS_ERR(drvdata->atclk))
+ clk_prepare_enable(drvdata->atclk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops replicator_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
+ replicator_runtime_resume, NULL)
+};
+
static const struct of_device_id replicator_match[] = {
{.compatible = "arm,coresight-replicator"},
{}
.driver = {
.name = "coresight-replicator",
.of_match_table = replicator_match,
+ .pm = &replicator_dev_pm_ops,
},
};