2 * linux/drivers/media/video/samsung/mfc5x/mfc_pm.c
4 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
7 * Power management module for Samsung MFC (Multi Function Codec - FIMV) driver
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/err.h>
15 #include <linux/clk.h>
16 #include <linux/delay.h>
17 #ifdef CONFIG_PM_RUNTIME
18 #include <linux/pm_runtime.h>
20 #include <linux/interrupt.h>
22 #include <plat/clock.h>
23 #include <plat/s5p-mfc.h>
26 #include <mach/regs-pmu.h>
33 #define MFC_PARENT_CLK_NAME "mout_mfc0"
34 #define MFC_CLKNAME "sclk_mfc"
35 #define MFC_GATE_CLK_NAME "mfc"
39 static struct mfc_pm *pm;
45 int mfc_init_pm(struct mfc_dev *mfcdev)
47 struct clk *parent, *sclk;
52 parent = clk_get(mfcdev->device, MFC_PARENT_CLK_NAME);
54 printk(KERN_ERR "failed to get parent clock\n");
59 sclk = clk_get(mfcdev->device, MFC_CLKNAME);
61 printk(KERN_ERR "failed to get source clock\n");
66 ret = clk_set_parent(sclk, parent);
68 printk(KERN_ERR "unable to set parent %s of clock %s\n",
69 parent->name, sclk->name);
73 /* FIXME: clock name & rate have to move to machine code */
74 ret = clk_set_rate(sclk, mfc_clk_rate);
76 printk(KERN_ERR "%s rate change failed: %u\n", sclk->name, 200 * 1000000);
80 /* clock for gating */
81 pm->clock = clk_get(mfcdev->device, MFC_GATE_CLK_NAME);
82 if (IS_ERR(pm->clock)) {
83 printk(KERN_ERR "failed to get clock-gating control\n");
88 atomic_set(&pm->power, 0);
90 #ifdef CONFIG_PM_RUNTIME
91 pm->device = mfcdev->device;
92 pm_runtime_enable(pm->device);
96 atomic_set(&clk_ref, 0);
111 void mfc_final_pm(struct mfc_dev *mfcdev)
113 #ifdef CONFIG_PM_RUNTIME
114 pm_runtime_disable(pm->device);
118 int mfc_clock_on(struct mfc_dev *mfcdev)
122 atomic_inc(&clk_ref);
123 mfc_dbg("+ %d", atomic_read(&clk_ref));
126 ret = clk_enable(pm->clock);
127 enable_irq(mfcdev->irq);
131 void mfc_clock_off(struct mfc_dev *mfcdev)
134 atomic_dec(&clk_ref);
135 mfc_dbg("- %d", atomic_read(&clk_ref));
137 disable_irq(mfcdev->irq);
138 clk_disable(pm->clock);
141 int mfc_power_on(void)
143 #ifdef CONFIG_PM_RUNTIME
144 if ((soc_is_exynos4212() && (samsung_rev() < EXYNOS4212_REV_1_0)) ||
145 (soc_is_exynos4412() && (samsung_rev() < EXYNOS4412_REV_1_1)))
148 return pm_runtime_get_sync(pm->device);
150 atomic_set(&pm->power, 1);
156 int mfc_power_off(void)
158 #ifdef CONFIG_PM_RUNTIME
159 if ((soc_is_exynos4212() && (samsung_rev() < EXYNOS4212_REV_1_0)) ||
160 (soc_is_exynos4412() && (samsung_rev() < EXYNOS4412_REV_1_1)))
163 return pm_runtime_put_sync(pm->device);
165 atomic_set(&pm->power, 0);
171 bool mfc_power_chk(void)
173 mfc_dbg("%s", atomic_read(&pm->power) ? "on" : "off");
175 return atomic_read(&pm->power) ? true : false;
178 void mfc_pd_enable(void)
182 __raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_PMU_MFC_CONF);
186 while ((__raw_readl(S5P_PMU_MFC_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN)
187 != S5P_INT_LOCAL_PWR_EN) {
189 printk(KERN_ERR "Power domain MFC enable failed.\n");