Linux 4.19.133
[linux/fpc-iii.git] / drivers / media / platform / s5p-mfc / s5p_mfc_pm.c
blob5e080f32b0e8247324ea513151cb97c362edd44a
1 /*
2 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
4 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
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.
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"
21 static struct s5p_mfc_pm *pm;
22 static struct s5p_mfc_dev *p_dev;
23 static atomic_t clk_ref;
25 int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
27 int i;
29 pm = &dev->pm;
30 p_dev = dev;
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;
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;
46 mfc_err("Failed to get clock: %s\n",
47 pm->clk_names[i]);
48 return PTR_ERR(pm->clocks[i]);
52 if (dev->variant->use_clock_gating)
53 pm->clock_gate = pm->clocks[0];
55 pm_runtime_enable(pm->device);
56 atomic_set(&clk_ref, 0);
57 return 0;
60 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
62 pm_runtime_disable(pm->device);
65 int s5p_mfc_clock_on(void)
67 atomic_inc(&clk_ref);
68 mfc_debug(3, "+ %d\n", atomic_read(&clk_ref));
70 return clk_enable(pm->clock_gate);
73 void s5p_mfc_clock_off(void)
75 atomic_dec(&clk_ref);
76 mfc_debug(3, "- %d\n", atomic_read(&clk_ref));
78 clk_disable(pm->clock_gate);
81 int s5p_mfc_power_on(void)
83 int i, ret = 0;
85 ret = pm_runtime_get_sync(pm->device);
86 if (ret < 0)
87 return ret;
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;
100 /* prepare for software clock gating */
101 clk_disable(pm->clock_gate);
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;
111 int s5p_mfc_power_off(void)
113 int i;
115 /* finish software clock gating */
116 clk_enable(pm->clock_gate);
118 for (i = 0; i < pm->num_clocks; i++)
119 clk_disable_unprepare(pm->clocks[i]);
121 return pm_runtime_put_sync(pm->device);