treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152
[linux-2.6-block.git] / drivers / media / platform / s5p-mfc / s5p_mfc_pm.c
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
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                         mfc_err("Failed to get clock: %s\n",
38                                 pm->clk_names[i]);
39                         return PTR_ERR(pm->clocks[i]);
40                 }
41         }
42
43         if (dev->variant->use_clock_gating)
44                 pm->clock_gate = pm->clocks[0];
45
46         pm_runtime_enable(pm->device);
47         atomic_set(&clk_ref, 0);
48         return 0;
49 }
50
51 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
52 {
53         pm_runtime_disable(pm->device);
54 }
55
56 int s5p_mfc_clock_on(void)
57 {
58         atomic_inc(&clk_ref);
59         mfc_debug(3, "+ %d\n", atomic_read(&clk_ref));
60
61         return clk_enable(pm->clock_gate);
62 }
63
64 void s5p_mfc_clock_off(void)
65 {
66         atomic_dec(&clk_ref);
67         mfc_debug(3, "- %d\n", atomic_read(&clk_ref));
68
69         clk_disable(pm->clock_gate);
70 }
71
72 int s5p_mfc_power_on(void)
73 {
74         int i, ret = 0;
75
76         ret = pm_runtime_get_sync(pm->device);
77         if (ret < 0)
78                 return ret;
79
80         /* clock control */
81         for (i = 0; i < pm->num_clocks; i++) {
82                 ret = clk_prepare_enable(pm->clocks[i]);
83                 if (ret < 0) {
84                         mfc_err("clock prepare failed for clock: %s\n",
85                                 pm->clk_names[i]);
86                         i++;
87                         goto err;
88                 }
89         }
90
91         /* prepare for software clock gating */
92         clk_disable(pm->clock_gate);
93
94         return 0;
95 err:
96         while (--i > 0)
97                 clk_disable_unprepare(pm->clocks[i]);
98         pm_runtime_put(pm->device);
99         return ret;
100 }
101
102 int s5p_mfc_power_off(void)
103 {
104         int i;
105
106         /* finish software clock gating */
107         clk_enable(pm->clock_gate);
108
109         for (i = 0; i < pm->num_clocks; i++)
110                 clk_disable_unprepare(pm->clocks[i]);
111
112         return pm_runtime_put_sync(pm->device);
113 }
114