• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
3  *
4  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
5  *		http://www.samsung.com/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12 
13 #include <linux/clk.h>
14 #include <linux/err.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include "s5p_mfc_common.h"
18 #include "s5p_mfc_debug.h"
19 #include "s5p_mfc_pm.h"
20 
21 static struct s5p_mfc_pm *pm;
22 static struct s5p_mfc_dev *p_dev;
23 static atomic_t clk_ref;
24 
s5p_mfc_init_pm(struct s5p_mfc_dev * dev)25 int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
26 {
27 	int i;
28 
29 	pm = &dev->pm;
30 	p_dev = dev;
31 
32 	pm->num_clocks = dev->variant->num_clocks;
33 	pm->clk_names = dev->variant->clk_names;
34 	pm->device = &dev->plat_dev->dev;
35 	pm->clock_gate = NULL;
36 
37 	/* clock control */
38 	for (i = 0; i < pm->num_clocks; i++) {
39 		pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]);
40 		if (IS_ERR(pm->clocks[i])) {
41 			/* additional clocks are optional */
42 			if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) {
43 				pm->clocks[i] = NULL;
44 				continue;
45 			}
46 			mfc_err("Failed to get clock: %s\n",
47 				pm->clk_names[i]);
48 			return PTR_ERR(pm->clocks[i]);
49 		}
50 	}
51 
52 	if (dev->variant->use_clock_gating)
53 		pm->clock_gate = pm->clocks[0];
54 
55 	pm_runtime_enable(pm->device);
56 	atomic_set(&clk_ref, 0);
57 	return 0;
58 }
59 
s5p_mfc_final_pm(struct s5p_mfc_dev * dev)60 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
61 {
62 	pm_runtime_disable(pm->device);
63 }
64 
s5p_mfc_clock_on(void)65 int s5p_mfc_clock_on(void)
66 {
67 	atomic_inc(&clk_ref);
68 	mfc_debug(3, "+ %d\n", atomic_read(&clk_ref));
69 
70 	return clk_enable(pm->clock_gate);
71 }
72 
s5p_mfc_clock_off(void)73 void s5p_mfc_clock_off(void)
74 {
75 	atomic_dec(&clk_ref);
76 	mfc_debug(3, "- %d\n", atomic_read(&clk_ref));
77 
78 	clk_disable(pm->clock_gate);
79 }
80 
s5p_mfc_power_on(void)81 int s5p_mfc_power_on(void)
82 {
83 	int i, ret = 0;
84 
85 	ret = pm_runtime_get_sync(pm->device);
86 	if (ret < 0)
87 		return ret;
88 
89 	/* clock control */
90 	for (i = 0; i < pm->num_clocks; i++) {
91 		ret = clk_prepare_enable(pm->clocks[i]);
92 		if (ret < 0) {
93 			mfc_err("clock prepare failed for clock: %s\n",
94 				pm->clk_names[i]);
95 			i++;
96 			goto err;
97 		}
98 	}
99 
100 	/* prepare for software clock gating */
101 	clk_disable(pm->clock_gate);
102 
103 	return 0;
104 err:
105 	while (--i > 0)
106 		clk_disable_unprepare(pm->clocks[i]);
107 	pm_runtime_put(pm->device);
108 	return ret;
109 }
110 
s5p_mfc_power_off(void)111 int s5p_mfc_power_off(void)
112 {
113 	int i;
114 
115 	/* finish software clock gating */
116 	clk_enable(pm->clock_gate);
117 
118 	for (i = 0; i < pm->num_clocks; i++)
119 		clk_disable_unprepare(pm->clocks[i]);
120 
121 	return pm_runtime_put_sync(pm->device);
122 }
123 
124