xref: /linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * linux/drivers/media/platform/samsung/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 
s5p_mfc_init_pm(struct s5p_mfc_dev * dev)17 int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
18 {
19 	struct s5p_mfc_pm *pm = &dev->pm;
20 	int i;
21 
22 	pm->num_clocks = dev->variant->num_clocks;
23 	pm->clk_names = dev->variant->clk_names;
24 	pm->device = &dev->plat_dev->dev;
25 	pm->clock_gate = NULL;
26 
27 	/* clock control */
28 	for (i = 0; i < pm->num_clocks; i++) {
29 		pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]);
30 		if (IS_ERR(pm->clocks[i])) {
31 			/* additional clocks are optional */
32 			if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) {
33 				pm->clocks[i] = NULL;
34 				continue;
35 			}
36 			mfc_err("Failed to get clock: %s\n",
37 				pm->clk_names[i]);
38 			return PTR_ERR(pm->clocks[i]);
39 		}
40 	}
41 
42 	if (dev->variant->use_clock_gating)
43 		pm->clock_gate = pm->clocks[0];
44 
45 	pm_runtime_enable(pm->device);
46 	return 0;
47 }
48 
s5p_mfc_final_pm(struct s5p_mfc_dev * dev)49 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
50 {
51 	pm_runtime_disable(dev->pm.device);
52 }
53 
s5p_mfc_clock_on(struct s5p_mfc_dev * dev)54 int s5p_mfc_clock_on(struct s5p_mfc_dev *dev)
55 {
56 	return clk_enable(dev->pm.clock_gate);
57 }
58 
s5p_mfc_clock_off(struct s5p_mfc_dev * dev)59 void s5p_mfc_clock_off(struct s5p_mfc_dev *dev)
60 {
61 	clk_disable(dev->pm.clock_gate);
62 }
63 
s5p_mfc_power_on(struct s5p_mfc_dev * dev)64 int s5p_mfc_power_on(struct s5p_mfc_dev *dev)
65 {
66 	int i, ret = 0;
67 
68 	ret = pm_runtime_resume_and_get(dev->pm.device);
69 	if (ret < 0)
70 		return ret;
71 
72 	/* clock control */
73 	for (i = 0; i < dev->pm.num_clocks; i++) {
74 		ret = clk_prepare_enable(dev->pm.clocks[i]);
75 		if (ret < 0) {
76 			mfc_err("clock prepare failed for clock: %s\n",
77 				dev->pm.clk_names[i]);
78 			goto err;
79 		}
80 	}
81 
82 	/* prepare for software clock gating */
83 	clk_disable(dev->pm.clock_gate);
84 
85 	return 0;
86 err:
87 	while (--i >= 0)
88 		clk_disable_unprepare(dev->pm.clocks[i]);
89 	pm_runtime_put(dev->pm.device);
90 	return ret;
91 }
92 
s5p_mfc_power_off(struct s5p_mfc_dev * dev)93 int s5p_mfc_power_off(struct s5p_mfc_dev *dev)
94 {
95 	int i;
96 
97 	/* finish software clock gating */
98 	clk_enable(dev->pm.clock_gate);
99 
100 	for (i = 0; i < dev->pm.num_clocks; i++)
101 		clk_disable_unprepare(dev->pm.clocks[i]);
102 
103 	return pm_runtime_put_sync(dev->pm.device);
104 }
105 
106