/*1* Based on arch/arm/plat-omap/clock.c2*3* Copyright (C) 2004 - 2005 Nokia corporation4* Written by Tuukka Tikkanen <[email protected]>5* Modified for omap shared clock framework by Tony Lindgren <[email protected]>6* Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.7* Copyright 2008 Juergen Beisert, [email protected]8*9* This program is free software; you can redistribute it and/or10* modify it under the terms of the GNU General Public License11* as published by the Free Software Foundation; either version 212* of the License, or (at your option) any later version.13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,21* MA 02110-1301, USA.22*/2324/* #define DEBUG */2526#include <linux/clk.h>27#include <linux/err.h>28#include <linux/errno.h>29#include <linux/init.h>30#include <linux/io.h>31#include <linux/kernel.h>32#include <linux/list.h>33#include <linux/module.h>34#include <linux/mutex.h>35#include <linux/platform_device.h>36#include <linux/proc_fs.h>37#include <linux/semaphore.h>38#include <linux/string.h>3940#include <mach/clock.h>4142static LIST_HEAD(clocks);43static DEFINE_MUTEX(clocks_mutex);4445/*-------------------------------------------------------------------------46* Standard clock functions defined in include/linux/clk.h47*-------------------------------------------------------------------------*/4849static void __clk_disable(struct clk *clk)50{51if (clk == NULL || IS_ERR(clk))52return;53WARN_ON(!clk->usecount);5455if (!(--clk->usecount)) {56if (clk->disable)57clk->disable(clk);58__clk_disable(clk->parent);59}60}6162static int __clk_enable(struct clk *clk)63{64if (clk == NULL || IS_ERR(clk))65return -EINVAL;6667if (clk->usecount++ == 0) {68__clk_enable(clk->parent);6970if (clk->enable)71clk->enable(clk);72}73return 0;74}7576/* This function increments the reference count on the clock and enables the77* clock if not already enabled. The parent clock tree is recursively enabled78*/79int clk_enable(struct clk *clk)80{81int ret = 0;8283if (clk == NULL || IS_ERR(clk))84return -EINVAL;8586mutex_lock(&clocks_mutex);87ret = __clk_enable(clk);88mutex_unlock(&clocks_mutex);8990return ret;91}92EXPORT_SYMBOL(clk_enable);9394/* This function decrements the reference count on the clock and disables95* the clock when reference count is 0. The parent clock tree is96* recursively disabled97*/98void clk_disable(struct clk *clk)99{100if (clk == NULL || IS_ERR(clk))101return;102103mutex_lock(&clocks_mutex);104__clk_disable(clk);105mutex_unlock(&clocks_mutex);106}107EXPORT_SYMBOL(clk_disable);108109/* Retrieve the *current* clock rate. If the clock itself110* does not provide a special calculation routine, ask111* its parent and so on, until one is able to return112* a valid clock rate113*/114unsigned long clk_get_rate(struct clk *clk)115{116if (clk == NULL || IS_ERR(clk))117return 0UL;118119if (clk->get_rate)120return clk->get_rate(clk);121122return clk_get_rate(clk->parent);123}124EXPORT_SYMBOL(clk_get_rate);125126/* Round the requested clock rate to the nearest supported127* rate that is less than or equal to the requested rate.128* This is dependent on the clock's current parent.129*/130long clk_round_rate(struct clk *clk, unsigned long rate)131{132if (clk == NULL || IS_ERR(clk) || !clk->round_rate)133return 0;134135return clk->round_rate(clk, rate);136}137EXPORT_SYMBOL(clk_round_rate);138139/* Set the clock to the requested clock rate. The rate must140* match a supported rate exactly based on what clk_round_rate returns141*/142int clk_set_rate(struct clk *clk, unsigned long rate)143{144int ret = -EINVAL;145146if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0)147return ret;148149mutex_lock(&clocks_mutex);150ret = clk->set_rate(clk, rate);151mutex_unlock(&clocks_mutex);152153return ret;154}155EXPORT_SYMBOL(clk_set_rate);156157/* Set the clock's parent to another clock source */158int clk_set_parent(struct clk *clk, struct clk *parent)159{160int ret = -EINVAL;161struct clk *old;162163if (clk == NULL || IS_ERR(clk) || parent == NULL ||164IS_ERR(parent) || clk->set_parent == NULL)165return ret;166167if (clk->usecount)168clk_enable(parent);169170mutex_lock(&clocks_mutex);171ret = clk->set_parent(clk, parent);172if (ret == 0) {173old = clk->parent;174clk->parent = parent;175} else {176old = parent;177}178mutex_unlock(&clocks_mutex);179180if (clk->usecount)181clk_disable(old);182183return ret;184}185EXPORT_SYMBOL(clk_set_parent);186187/* Retrieve the clock's parent clock source */188struct clk *clk_get_parent(struct clk *clk)189{190struct clk *ret = NULL;191192if (clk == NULL || IS_ERR(clk))193return ret;194195return clk->parent;196}197EXPORT_SYMBOL(clk_get_parent);198199200