diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 244 |
1 files changed, 155 insertions, 89 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 1e2fd404651..48b0cdf97ce 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -36,6 +36,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #include <video/omapdss.h> #include <plat/clock.h> @@ -267,8 +268,12 @@ struct dsi_isr_tables { struct dsi_data { struct platform_device *pdev; void __iomem *base; + int irq; + struct clk *dss_clk; + struct clk *sys_clk; + void (*dsi_mux_pads)(bool enable); struct dsi_clock_info current_cinfo; @@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, return __raw_readl(dsi->base + idx.idx); } - -void dsi_save_context(void) -{ -} - -void dsi_restore_context(void) -{ -} - void dsi_bus_lock(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -1048,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev) return e; } -/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ -static inline void enable_clocks(bool enable) +int dsi_runtime_get(struct platform_device *dsidev) { - if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + int r; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + DSSDBG("dsi_runtime_get\n"); + + r = pm_runtime_get_sync(&dsi->pdev->dev); + WARN_ON(r < 0); + return r < 0 ? r : 0; +} + +void dsi_runtime_put(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int r; + + DSSDBG("dsi_runtime_put\n"); + + r = pm_runtime_put(&dsi->pdev->dev); + WARN_ON(r < 0); } /* source clock for DSI PLL. this could also be PCLKFREE */ @@ -1064,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (enable) - dss_clk_enable(DSS_CLK_SYSCK); + clk_enable(dsi->sys_clk); else - dss_clk_disable(DSS_CLK_SYSCK); + clk_disable(dsi->sys_clk); if (enable && dsi->pll_locked) { if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) @@ -1159,10 +1169,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; int dsi_module = dsi_get_dsidev_id(dsidev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ - r = dss_clk_get_rate(DSS_CLK_FCK); + r = clk_get_rate(dsi->dss_clk); } else { /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ r = dsi_get_pll_hsdiv_dsi_rate(dsidev); @@ -1271,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, return -EINVAL; if (cinfo->use_sys_clk) { - cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); + cinfo->clkin = clk_get_rate(dsi->sys_clk); /* XXX it is unclear if highfreq should be used * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; @@ -1320,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, int match = 0; unsigned long dss_sys_clk, max_dss_fck; - dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); + dss_sys_clk = clk_get_rate(dsi->sys_clk); max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); @@ -1610,7 +1621,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, dsi->vdds_dsi_reg = vdds_dsi; } - enable_clocks(1); dsi_enable_pll_clock(dsidev, 1); /* * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. @@ -1662,7 +1672,6 @@ err1: } err0: dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); return r; } @@ -1680,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) } dsi_disable_scp_clk(dsidev); - enable_clocks(0); dsi_enable_pll_clock(dsidev, 0); DSSDBG("PLL uninit done\n"); @@ -1697,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, dispc_clk_src = dss_get_dispc_clk_source(); dsi_clk_src = dss_get_dsi_clk_source(dsi_module); - enable_clocks(1); + if (dsi_runtime_get(dsidev)) + return; seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); @@ -1740,7 +1749,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk); - enable_clocks(0); + dsi_runtime_put(dsidev); } void dsi_dump_clocks(struct seq_file *s) @@ -1882,7 +1891,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + if (dsi_runtime_get(dsidev)) + return; dsi_enable_scp_clk(dsidev); DUMPREG(DSI_REVISION); @@ -1956,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, DUMPREG(DSI_PLL_CONFIGURATION2); dsi_disable_scp_clk(dsidev); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); + dsi_runtime_put(dsidev); #undef DUMPREG } @@ -2472,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev) dsi->dsi_mux_pads(false); } -static int _dsi_wait_reset(struct platform_device *dsidev) -{ - int t = 0; - - while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) { - if (++t > 5) { - DSSERR("soft reset failed\n"); - return -ENODEV; - } - udelay(1); - } - - return 0; -} - -static int _dsi_reset(struct platform_device *dsidev) -{ - /* Soft reset */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1); - return _dsi_wait_reset(dsidev); -} - static void dsi_config_tx_fifo(struct platform_device *dsidev, enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) @@ -4211,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_pll_uninit(dsidev, disconnect_lanes); } -static int dsi_core_init(struct platform_device *dsidev) -{ - /* Autoidle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0); - - /* ENWAKEUP */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2); - - /* SIDLEMODE smart-idle */ - REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3); - - _dsi_initialize_irq(dsidev); - - return 0; -} - int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -4242,37 +4214,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); - goto err0; + goto err_start_dev; } - enable_clocks(1); - dsi_enable_pll_clock(dsidev, 1); - - r = _dsi_reset(dsidev); + r = dsi_runtime_get(dsidev); if (r) - goto err1; + goto err_get_dsi; + + dsi_enable_pll_clock(dsidev, 1); - dsi_core_init(dsidev); + _dsi_initialize_irq(dsidev); r = dsi_display_init_dispc(dssdev); if (r) - goto err1; + goto err_init_dispc; r = dsi_display_init_dsi(dssdev); if (r) - goto err2; + goto err_init_dsi; mutex_unlock(&dsi->lock); return 0; -err2: +err_init_dsi: dsi_display_uninit_dispc(dssdev); -err1: - enable_clocks(0); +err_init_dispc: dsi_enable_pll_clock(dsidev, 0); + dsi_runtime_put(dsidev); +err_get_dsi: omap_dss_stop_device(dssdev); -err0: +err_start_dev: mutex_unlock(&dsi->lock); DSSDBG("dsi_display_enable FAILED\n"); return r; @@ -4300,7 +4272,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); - enable_clocks(0); + dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); omap_dss_stop_device(dssdev); @@ -4450,6 +4422,42 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); } +static int dsi_get_clocks(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct clk *clk; + + clk = clk_get(&dsidev->dev, "fck"); + if (IS_ERR(clk)) { + DSSERR("can't get fck\n"); + return PTR_ERR(clk); + } + + dsi->dss_clk = clk; + + clk = clk_get(&dsidev->dev, "sys_clk"); + if (IS_ERR(clk)) { + DSSERR("can't get sys_clk\n"); + clk_put(dsi->dss_clk); + dsi->dss_clk = NULL; + return PTR_ERR(clk); + } + + dsi->sys_clk = clk; + + return 0; +} + +static void dsi_put_clocks(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + if (dsi->dss_clk) + clk_put(dsi->dss_clk); + if (dsi->sys_clk) + clk_put(dsi->sys_clk); +} + /* DSI1 HW IP initialisation */ static int omap_dsi1hw_probe(struct platform_device *dsidev) { @@ -4463,7 +4471,7 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) { r = -ENOMEM; - goto err0; + goto err_alloc; } dsi->pdev = dsidev; @@ -4486,6 +4494,12 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) mutex_init(&dsi->lock); sema_init(&dsi->bus_lock, 1); + r = dsi_get_clocks(dsidev); + if (r) + goto err_get_clk; + + pm_runtime_enable(&dsidev->dev); + INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -4498,26 +4512,26 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) if (!dsi_mem) { DSSERR("can't get IORESOURCE_MEM DSI\n"); r = -EINVAL; - goto err1; + goto err_ioremap; } dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); if (!dsi->base) { DSSERR("can't ioremap DSI\n"); r = -ENOMEM; - goto err1; + goto err_ioremap; } dsi->irq = platform_get_irq(dsi->pdev, 0); if (dsi->irq < 0) { DSSERR("platform_get_irq failed\n"); r = -ENODEV; - goto err2; + goto err_get_irq; } r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); if (r < 0) { DSSERR("request_irq failed\n"); - goto err2; + goto err_get_irq; } /* DSI VCs initialization */ @@ -4529,7 +4543,9 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi_calc_clock_param_ranges(dsidev); - enable_clocks(1); + r = dsi_runtime_get(dsidev); + if (r) + goto err_get_dsi; rev = dsi_read_reg(dsidev, DSI_REVISION); dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", @@ -4537,14 +4553,19 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); - enable_clocks(0); + dsi_runtime_put(dsidev); return 0; -err2: + +err_get_dsi: + free_irq(dsi->irq, dsi->pdev); +err_get_irq: iounmap(dsi->base); -err1: +err_ioremap: + pm_runtime_disable(&dsidev->dev); +err_get_clk: kfree(dsi); -err0: +err_alloc: return r; } @@ -4554,6 +4575,10 @@ static int omap_dsi1hw_remove(struct platform_device *dsidev) WARN_ON(dsi->scp_clk_refcount > 0); + pm_runtime_disable(&dsidev->dev); + + dsi_put_clocks(dsidev); + if (dsi->vdds_dsi_reg != NULL) { if (dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); @@ -4572,12 +4597,53 @@ static int omap_dsi1hw_remove(struct platform_device *dsidev) return 0; } +static int dsi_runtime_suspend(struct device *dev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); + + clk_disable(dsi->dss_clk); + + dispc_runtime_put(); + dss_runtime_put(); + + return 0; +} + +static int dsi_runtime_resume(struct device *dev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); + int r; + + r = dss_runtime_get(); + if (r) + goto err_get_dss; + + r = dispc_runtime_get(); + if (r) + goto err_get_dispc; + + clk_enable(dsi->dss_clk); + + return 0; + +err_get_dispc: + dss_runtime_put(); +err_get_dss: + return r; +} + +static const struct dev_pm_ops dsi_pm_ops = { + .runtime_suspend = dsi_runtime_suspend, + .runtime_resume = dsi_runtime_resume, +}; + static struct platform_driver omap_dsi1hw_driver = { .probe = omap_dsi1hw_probe, .remove = omap_dsi1hw_remove, .driver = { .name = "omapdss_dsi1", .owner = THIS_MODULE, + .pm = &dsi_pm_ops, }, }; |