OMAP: DSS2: check for manager when enabling display
[deliverable/linux.git] / drivers / video / omap2 / dss / rfbi.c
index c06fbe0bc6789bee3c32a796b1b9efdb4efc763d..1bb8ce11f6bce229f3f82d46c14a714e7c8d6138 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
 #include <linux/semaphore.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
        return __raw_readl(rfbi.base + idx.idx);
 }
 
-static void rfbi_enable_clocks(bool enable)
+static int rfbi_runtime_get(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+
+       DSSDBG("rfbi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void rfbi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("rfbi_runtime_put\n");
+
+       r = pm_runtime_put(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
 }
 
 void rfbi_bus_lock(void)
@@ -805,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (rfbi_runtime_get())
+               return;
 
        DUMPREG(RFBI_REVISION);
        DUMPREG(RFBI_SYSCONFIG);
@@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
        DUMPREG(RFBI_VSYNC_WIDTH);
        DUMPREG(RFBI_HSYNC_WIDTH);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       rfbi_runtime_put();
 #undef DUMPREG
 }
 
@@ -844,7 +860,14 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
-       rfbi_enable_clocks(1);
+       if (dssdev->manager == NULL) {
+               DSSERR("failed to enable display: no manager\n");
+               return -ENODEV;
+       }
+
+       r = rfbi_runtime_get();
+       if (r)
+               return r;
 
        r = omap_dss_start_device(dssdev);
        if (r) {
@@ -879,6 +902,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 err1:
        omap_dss_stop_device(dssdev);
 err0:
+       rfbi_runtime_put();
        return r;
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_enable);
@@ -889,7 +913,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
                        DISPC_IRQ_FRAMEDONE);
        omap_dss_stop_device(dssdev);
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -904,8 +928,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
 static int omap_rfbihw_probe(struct platform_device *pdev)
 {
        u32 rev;
-       u32 l;
        struct resource *rfbi_mem;
+       struct clk *clk;
+       int r;
 
        rfbi.pdev = pdev;
 
@@ -914,46 +939,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
        rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
        if (!rfbi_mem) {
                DSSERR("can't get IORESOURCE_MEM RFBI\n");
-               return -EINVAL;
+               r = -EINVAL;
+               goto err_ioremap;
        }
        rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
        if (!rfbi.base) {
                DSSERR("can't ioremap RFBI\n");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_ioremap;
        }
 
-       rfbi_enable_clocks(1);
+       pm_runtime_enable(&pdev->dev);
+
+       r = rfbi_runtime_get();
+       if (r)
+               goto err_get_rfbi;
 
        msleep(10);
 
-       rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+       if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630())
+               clk = dss_get_ick();
+       else
+               clk = clk_get(&pdev->dev, "ick");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get ick\n");
+               r = PTR_ERR(clk);
+               goto err_get_ick;
+       }
 
-       /* Enable autoidle and smart-idle */
-       l = rfbi_read_reg(RFBI_SYSCONFIG);
-       l |= (1 << 0) | (2 << 3);
-       rfbi_write_reg(RFBI_SYSCONFIG, l);
+       rfbi.l4_khz = clk_get_rate(clk) / 1000;
+
+       clk_put(clk);
 
        rev = rfbi_read_reg(RFBI_REVISION);
        dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 
        return 0;
+
+err_get_ick:
+       rfbi_runtime_put();
+err_get_rfbi:
+       pm_runtime_disable(&pdev->dev);
+       iounmap(rfbi.base);
+err_ioremap:
+       return r;
 }
 
 static int omap_rfbihw_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
        iounmap(rfbi.base);
        return 0;
 }
 
+static int rfbi_runtime_suspend(struct device *dev)
+{
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int rfbi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops rfbi_pm_ops = {
+       .runtime_suspend = rfbi_runtime_suspend,
+       .runtime_resume = rfbi_runtime_resume,
+};
+
 static struct platform_driver omap_rfbihw_driver = {
        .probe          = omap_rfbihw_probe,
        .remove         = omap_rfbihw_remove,
        .driver         = {
                .name   = "omapdss_rfbi",
                .owner  = THIS_MODULE,
+               .pm     = &rfbi_pm_ops,
        },
 };
 
This page took 0.04137 seconds and 5 git commands to generate.