diff options
Diffstat (limited to 'drivers/mxc/ipu3/ipu_common.c')
-rw-r--r-- | drivers/mxc/ipu3/ipu_common.c | 91 |
1 files changed, 56 insertions, 35 deletions
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 7aa9640aed7a..76d34ce20c60 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -45,7 +45,6 @@ struct ipu_irq_node { /* Globals */ struct clk *g_ipu_clk; -bool g_ipu_clk_enabled; struct clk *g_di_clk[2]; struct clk *g_pixel_clk[2]; struct clk *g_csi_clk[2]; @@ -53,12 +52,14 @@ unsigned char g_dc_di_assignment[10]; ipu_channel_t g_ipu_csi_channel[2]; int g_ipu_irq[2]; int g_ipu_hw_rev; +int g_ipu_use_count; bool g_sec_chan_en[24]; bool g_thrd_chan_en[24]; bool g_chan_is_interlaced[52]; uint32_t g_channel_init_mask; uint32_t g_channel_enable_mask; DEFINE_SPINLOCK(ipu_lock); +DEFINE_MUTEX(ipu_clk_lock); struct device *g_ipu_dev; static struct ipu_irq_node ipu_irq_list[IPU_IRQ_COUNT]; @@ -275,6 +276,7 @@ static int ipu_probe(struct platform_device *pdev) unsigned long ipu_base; spin_lock_init(&ipu_lock); + mutex_init(&ipu_clk_lock); g_ipu_hw_rev = plat_data->rev; @@ -419,9 +421,43 @@ int ipu_remove(struct platform_device *pdev) iounmap(ipu_disp_base[1]); iounmap(ipu_vdi_reg); + mutex_destroy(&ipu_clk_lock); + return 0; } +void ipu_get_clk(bool stop_dvfs) +{ + mutex_lock(&ipu_clk_lock); + + g_ipu_use_count++; + + if (g_ipu_use_count == 1) { + if (stop_dvfs) + stop_dvfs_per(); + clk_enable(g_ipu_clk); + } + + mutex_unlock(&ipu_clk_lock); +} + +void ipu_put_clk(void) +{ + mutex_lock(&ipu_clk_lock); + + g_ipu_use_count--; + + if (g_ipu_use_count == 0) + clk_disable(g_ipu_clk); + + if (g_ipu_use_count < 0) { + dev_err(g_ipu_dev, "ipu use count < 0\n"); + g_ipu_use_count = 0; + } + + mutex_unlock(&ipu_clk_lock); +} + void ipu_dump_registers(void) { printk(KERN_DEBUG "IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF)); @@ -493,11 +529,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) __raw_writel(0xFFFFFFFF, IPU_INT_CTRL(9)); __raw_writel(0xFFFFFFFF, IPU_INT_CTRL(10)); - if (g_ipu_clk_enabled == false) { - stop_dvfs_per(); - g_ipu_clk_enabled = true; - clk_enable(g_ipu_clk); - } + ipu_get_clk(true); spin_lock_irqsave(&ipu_lock, lock_flags); @@ -956,10 +988,7 @@ void ipu_uninit_channel(ipu_channel_t channel) spin_unlock_irqrestore(&ipu_lock, lock_flags); - if (ipu_conf == 0) { - clk_disable(g_ipu_clk); - g_ipu_clk_enabled = false; - } + ipu_put_clk(); WARN_ON(ipu_ic_use_count < 0); WARN_ON(ipu_vdi_use_count < 0); @@ -2247,9 +2276,7 @@ void ipu_enable_irq(uint32_t irq) uint32_t reg; unsigned long lock_flags; - if (!g_ipu_clk_enabled) - clk_enable(g_ipu_clk); - + ipu_get_clk(false); spin_lock_irqsave(&ipu_lock, lock_flags); reg = __raw_readl(IPUIRQ_2_CTRLREG(irq)); @@ -2257,8 +2284,7 @@ void ipu_enable_irq(uint32_t irq) __raw_writel(reg, IPUIRQ_2_CTRLREG(irq)); spin_unlock_irqrestore(&ipu_lock, lock_flags); - if (!g_ipu_clk_enabled) - clk_disable(g_ipu_clk); + ipu_put_clk(); } EXPORT_SYMBOL(ipu_enable_irq); @@ -2274,8 +2300,6 @@ void ipu_disable_irq(uint32_t irq) uint32_t reg; unsigned long lock_flags; - if (!g_ipu_clk_enabled) - clk_enable(g_ipu_clk); spin_lock_irqsave(&ipu_lock, lock_flags); reg = __raw_readl(IPUIRQ_2_CTRLREG(irq)); @@ -2283,8 +2307,6 @@ void ipu_disable_irq(uint32_t irq) __raw_writel(reg, IPUIRQ_2_CTRLREG(irq)); spin_unlock_irqrestore(&ipu_lock, lock_flags); - if (!g_ipu_clk_enabled) - clk_disable(g_ipu_clk); } EXPORT_SYMBOL(ipu_disable_irq); @@ -2297,13 +2319,12 @@ EXPORT_SYMBOL(ipu_disable_irq); */ void ipu_clear_irq(uint32_t irq) { - if (!g_ipu_clk_enabled) - clk_enable(g_ipu_clk); + ipu_get_clk(false); __raw_writel(IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq)); - if (!g_ipu_clk_enabled) - clk_disable(g_ipu_clk); + ipu_put_clk(); + } EXPORT_SYMBOL(ipu_clear_irq); @@ -2320,13 +2341,11 @@ bool ipu_get_irq_status(uint32_t irq) { uint32_t reg; - if (!g_ipu_clk_enabled) - clk_enable(g_ipu_clk); + ipu_get_clk(false); reg = __raw_readl(IPUIRQ_2_STATREG(irq)); - if (!g_ipu_clk_enabled) - clk_disable(g_ipu_clk); + ipu_put_clk(); if (reg & IPUIRQ_2_MASK(irq)) return true; @@ -2398,7 +2417,9 @@ EXPORT_SYMBOL(ipu_request_irq); */ void ipu_free_irq(uint32_t irq, void *dev_id) { + ipu_get_clk(false); ipu_disable_irq(irq); /* disable the interrupt */ + ipu_put_clk(); if (ipu_irq_list[irq].dev_id == dev_id) ipu_irq_list[irq].handler = NULL; @@ -2592,14 +2613,12 @@ EXPORT_SYMBOL(ipu_set_csc_coefficients); static int ipu_suspend(struct platform_device *pdev, pm_message_t state) { -#ifdef CONFIG_ANDROID - ipu_disable_channel(MEM_FG_SYNC, true); - ipu_uninit_channel(MEM_FG_SYNC); -#endif - - if (g_ipu_clk_enabled) { + mutex_lock(&ipu_clk_lock); + if (g_ipu_use_count > 0) { uint32_t chan_should_disable, timeout = 1000, time = 0; + dev_err(g_ipu_dev, "ipu suspend with ipu clock enabled\n"); + /* save and disable enabled channels*/ idma_enable_reg[0] = __raw_readl(IDMAC_CHA_EN(0)); idma_enable_reg[1] = __raw_readl(IDMAC_CHA_EN(32)); @@ -2678,6 +2697,7 @@ static int ipu_suspend(struct platform_device *pdev, pm_message_t state) buf_ready_reg[8] = __raw_readl(IPU_CHA_BUF2_RDY(0)); buf_ready_reg[9] = __raw_readl(IPU_CHA_BUF2_RDY(32)); } + mutex_unlock(&ipu_clk_lock); mxc_pg_enable(pdev); @@ -2688,8 +2708,8 @@ static int ipu_resume(struct platform_device *pdev) { mxc_pg_disable(pdev); - if (g_ipu_clk_enabled) { - + mutex_lock(&ipu_clk_lock); + if (g_ipu_use_count > 0) { /* restore buf ready regs */ __raw_writel(buf_ready_reg[0], IPU_CHA_BUF0_RDY(0)); __raw_writel(buf_ready_reg[1], IPU_CHA_BUF0_RDY(32)); @@ -2753,6 +2773,7 @@ static int ipu_resume(struct platform_device *pdev) __raw_writel(0x18800001L, IDMAC_CHA_PRI(0)); clk_disable(g_ipu_clk); } + mutex_unlock(&ipu_clk_lock); return 0; } |