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 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 /* 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 56 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) 57 { 58 pm_runtime_disable(pm->device); 59 } 60 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 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 77 int s5p_mfc_power_on(void) 78 { 79 int i, ret = 0; 80 81 ret = pm_runtime_resume_and_get(pm->device); 82 if (ret < 0) 83 return ret; 84 85 /* clock control */ 86 for (i = 0; i < pm->num_clocks; i++) { 87 ret = clk_prepare_enable(pm->clocks[i]); 88 if (ret < 0) { 89 mfc_err("clock prepare failed for clock: %s\n", 90 pm->clk_names[i]); 91 goto err; 92 } 93 } 94 95 /* prepare for software clock gating */ 96 clk_disable(pm->clock_gate); 97 98 return 0; 99 err: 100 while (--i >= 0) 101 clk_disable_unprepare(pm->clocks[i]); 102 pm_runtime_put(pm->device); 103 return ret; 104 } 105 106 int s5p_mfc_power_off(void) 107 { 108 int i; 109 110 /* finish software clock gating */ 111 clk_enable(pm->clock_gate); 112 113 for (i = 0; i < pm->num_clocks; i++) 114 clk_disable_unprepare(pm->clocks[i]); 115 116 return pm_runtime_put_sync(pm->device); 117 } 118 119