1/* 2 * Based on arch/arm/plat-omap/clock.c 3 * 4 * Copyright (C) 2004 - 2005 Nokia corporation 5 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 6 * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> 7 * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. 8 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 22 * MA 02110-1301, USA. 23 */ 24 25/* #define DEBUG */ 26 27#include <linux/clk.h> 28#include <linux/err.h> 29#include <linux/errno.h> 30#include <linux/init.h> 31#include <linux/io.h> 32#include <linux/kernel.h> 33#include <linux/list.h> 34#include <linux/module.h> 35#include <linux/mutex.h> 36#include <linux/platform_device.h> 37#include <linux/proc_fs.h> 38#include <linux/semaphore.h> 39#include <linux/string.h> 40 41#include <mach/clock.h> 42 43static LIST_HEAD(clocks); 44static DEFINE_MUTEX(clocks_mutex); 45 46/*------------------------------------------------------------------------- 47 * Standard clock functions defined in include/linux/clk.h 48 *-------------------------------------------------------------------------*/ 49 50static void __clk_disable(struct clk *clk) 51{ 52 if (clk == NULL || IS_ERR(clk)) 53 return; 54 WARN_ON(!clk->usecount); 55 56 if (!(--clk->usecount)) { 57 if (clk->disable) 58 clk->disable(clk); 59 __clk_disable(clk->parent); 60 } 61} 62 63static int __clk_enable(struct clk *clk) 64{ 65 if (clk == NULL || IS_ERR(clk)) 66 return -EINVAL; 67 68 if (clk->usecount++ == 0) { 69 __clk_enable(clk->parent); 70 71 if (clk->enable) 72 clk->enable(clk); 73 } 74 return 0; 75} 76 77/* This function increments the reference count on the clock and enables the 78 * clock if not already enabled. The parent clock tree is recursively enabled 79 */ 80int clk_enable(struct clk *clk) 81{ 82 int ret = 0; 83 84 if (clk == NULL || IS_ERR(clk)) 85 return -EINVAL; 86 87 mutex_lock(&clocks_mutex); 88 ret = __clk_enable(clk); 89 mutex_unlock(&clocks_mutex); 90 91 return ret; 92} 93EXPORT_SYMBOL(clk_enable); 94 95/* This function decrements the reference count on the clock and disables 96 * the clock when reference count is 0. The parent clock tree is 97 * recursively disabled 98 */ 99void clk_disable(struct clk *clk) 100{ 101 if (clk == NULL || IS_ERR(clk)) 102 return; 103 104 mutex_lock(&clocks_mutex); 105 __clk_disable(clk); 106 mutex_unlock(&clocks_mutex); 107} 108EXPORT_SYMBOL(clk_disable); 109 110/* Retrieve the *current* clock rate. If the clock itself 111 * does not provide a special calculation routine, ask 112 * its parent and so on, until one is able to return 113 * a valid clock rate 114 */ 115unsigned long clk_get_rate(struct clk *clk) 116{ 117 if (clk == NULL || IS_ERR(clk)) 118 return 0UL; 119 120 if (clk->get_rate) 121 return clk->get_rate(clk); 122 123 return clk_get_rate(clk->parent); 124} 125EXPORT_SYMBOL(clk_get_rate); 126 127/* Round the requested clock rate to the nearest supported 128 * rate that is less than or equal to the requested rate. 129 * This is dependent on the clock's current parent. 130 */ 131long clk_round_rate(struct clk *clk, unsigned long rate) 132{ 133 if (clk == NULL || IS_ERR(clk) || !clk->round_rate) 134 return 0; 135 136 return clk->round_rate(clk, rate); 137} 138EXPORT_SYMBOL(clk_round_rate); 139 140/* Set the clock to the requested clock rate. The rate must 141 * match a supported rate exactly based on what clk_round_rate returns 142 */ 143int clk_set_rate(struct clk *clk, unsigned long rate) 144{ 145 int ret = -EINVAL; 146 147 if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) 148 return ret; 149 150 mutex_lock(&clocks_mutex); 151 ret = clk->set_rate(clk, rate); 152 mutex_unlock(&clocks_mutex); 153 154 return ret; 155} 156EXPORT_SYMBOL(clk_set_rate); 157 158/* Set the clock's parent to another clock source */ 159int clk_set_parent(struct clk *clk, struct clk *parent) 160{ 161 int ret = -EINVAL; 162 struct clk *old; 163 164 if (clk == NULL || IS_ERR(clk) || parent == NULL || 165 IS_ERR(parent) || clk->set_parent == NULL) 166 return ret; 167 168 if (clk->usecount) 169 clk_enable(parent); 170 171 mutex_lock(&clocks_mutex); 172 ret = clk->set_parent(clk, parent); 173 if (ret == 0) { 174 old = clk->parent; 175 clk->parent = parent; 176 } else { 177 old = parent; 178 } 179 mutex_unlock(&clocks_mutex); 180 181 if (clk->usecount) 182 clk_disable(old); 183 184 return ret; 185} 186EXPORT_SYMBOL(clk_set_parent); 187 188/* Retrieve the clock's parent clock source */ 189struct clk *clk_get_parent(struct clk *clk) 190{ 191 struct clk *ret = NULL; 192 193 if (clk == NULL || IS_ERR(clk)) 194 return ret; 195 196 return clk->parent; 197} 198EXPORT_SYMBOL(clk_get_parent); 199