1/* 2 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c 3 * 4 * Copyright (c) 2010 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * 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. 11 */ 12 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" 20 21static struct s5p_mfc_pm *pm; 22static struct s5p_mfc_dev *p_dev; 23static atomic_t clk_ref; 24 25int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) 26{ 27 int i; 28 29 pm = &dev->pm; 30 p_dev = dev; 31 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; 36 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 mfc_err("Failed to get clock: %s\n", 42 pm->clk_names[i]); 43 return PTR_ERR(pm->clocks[i]); 44 } 45 } 46 47 if (dev->variant->use_clock_gating) 48 pm->clock_gate = pm->clocks[0]; 49 50 pm_runtime_enable(pm->device); 51 atomic_set(&clk_ref, 0); 52 return 0; 53} 54 55void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) 56{ 57 pm_runtime_disable(pm->device); 58} 59 60int s5p_mfc_clock_on(void) 61{ 62 atomic_inc(&clk_ref); 63 mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); 64 65 return clk_enable(pm->clock_gate); 66} 67 68void s5p_mfc_clock_off(void) 69{ 70 atomic_dec(&clk_ref); 71 mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); 72 73 clk_disable(pm->clock_gate); 74} 75 76int s5p_mfc_power_on(void) 77{ 78 int i, ret = 0; 79 80 ret = pm_runtime_get_sync(pm->device); 81 if (ret < 0) 82 return ret; 83 84 /* clock control */ 85 for (i = 0; i < pm->num_clocks; i++) { 86 ret = clk_prepare_enable(pm->clocks[i]); 87 if (ret < 0) { 88 mfc_err("clock prepare failed for clock: %s\n", 89 pm->clk_names[i]); 90 i++; 91 goto err; 92 } 93 } 94 95 /* prepare for software clock gating */ 96 clk_disable(pm->clock_gate); 97 98 return 0; 99err: 100 while (--i > 0) 101 clk_disable_unprepare(pm->clocks[i]); 102 pm_runtime_put(pm->device); 103 return ret; 104} 105 106int 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