#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <drm/exynos_drm.h>
#include <plat/regs-fb-v4.h>
unsigned long irq_flags;
u32 vidcon0;
u32 vidcon1;
+ bool suspended;
struct fb_videomode *timing;
};
{
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
- /* TODO */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ pm_runtime_get_sync(subdrv_dev);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ pm_runtime_put_sync(subdrv_dev);
+ break;
+ default:
+ DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+ break;
+ }
}
static void fimd_apply(struct device *subdrv_dev)
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (ctx->suspended)
+ return -EPERM;
+
if (!test_and_set_bit(0, &ctx->irq_flags)) {
val = readl(ctx->regs + VIDINTCON0);
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (ctx->suspended)
+ return;
+
if (test_and_clear_bit(0, &ctx->irq_flags)) {
val = readl(ctx->regs + VIDINTCON0);
goto err_req_irq;
}
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
for (win = 0; win < WINDOWS_NR; win++)
fimd_clear_win(ctx, win);
static int __devexit fimd_remove(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct fimd_context *ctx = platform_get_drvdata(pdev);
DRM_DEBUG_KMS("%s\n", __FILE__);
exynos_drm_subdrv_unregister(&ctx->subdrv);
+ if (ctx->suspended)
+ goto out;
+
clk_disable(ctx->lcd_clk);
clk_disable(ctx->bus_clk);
+
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_sync(dev);
+
+out:
+ pm_runtime_disable(dev);
+
clk_put(ctx->lcd_clk);
clk_put(ctx->bus_clk);
return 0;
}
+#ifdef CONFIG_PM_RUNTIME
+static int fimd_runtime_suspend(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ clk_disable(ctx->lcd_clk);
+ clk_disable(ctx->bus_clk);
+
+ ctx->suspended = true;
+ return 0;
+}
+
+static int fimd_runtime_resume(struct device *dev)
+{
+ struct fimd_context *ctx = get_fimd_context(dev);
+ int ret;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ ret = clk_enable(ctx->bus_clk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_enable(ctx->lcd_clk);
+ if (ret < 0) {
+ clk_disable(ctx->bus_clk);
+ return ret;
+ }
+
+ ctx->suspended = false;
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops fimd_pm_ops = {
+ SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
+};
+
static struct platform_driver fimd_driver = {
.probe = fimd_probe,
.remove = __devexit_p(fimd_remove),
.driver = {
.name = "exynos4-fb",
.owner = THIS_MODULE,
+ .pm = &fimd_pm_ops,
},
};