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