| Hans J. Koch | da15797 | 2010-09-17 18:15:11 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | * Clock framework for Telechips SoCs | 
|  | 3 | * Based on arch/arm/plat-mxc/clock.c | 
|  | 4 | * | 
|  | 5 | * Copyright (C) 2004 - 2005 Nokia corporation | 
|  | 6 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 
|  | 7 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> | 
|  | 8 | * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. | 
|  | 9 | * Copyright 2008 Juergen Beisert, kernel@pengutronix.de | 
|  | 10 | * Copyright 2010 Hans J. Koch, hjk@linutronix.de | 
|  | 11 | * | 
|  | 12 | * Licensed under the terms of the GPL v2. | 
|  | 13 | */ | 
|  | 14 |  | 
|  | 15 | #include <linux/clk.h> | 
|  | 16 | #include <linux/err.h> | 
|  | 17 | #include <linux/errno.h> | 
|  | 18 | #include <linux/module.h> | 
|  | 19 | #include <linux/mutex.h> | 
|  | 20 | #include <linux/string.h> | 
|  | 21 |  | 
|  | 22 | #include <mach/clock.h> | 
|  | 23 | #include <mach/hardware.h> | 
|  | 24 |  | 
|  | 25 | static DEFINE_MUTEX(clocks_mutex); | 
|  | 26 |  | 
|  | 27 | /*------------------------------------------------------------------------- | 
|  | 28 | * Standard clock functions defined in include/linux/clk.h | 
|  | 29 | *-------------------------------------------------------------------------*/ | 
|  | 30 |  | 
|  | 31 | static void __clk_disable(struct clk *clk) | 
|  | 32 | { | 
|  | 33 | BUG_ON(clk->refcount == 0); | 
|  | 34 |  | 
|  | 35 | if (!(--clk->refcount) && clk->disable) { | 
|  | 36 | /* Unconditionally disable the clock in hardware */ | 
|  | 37 | clk->disable(clk); | 
|  | 38 | /* recursively disable parents */ | 
|  | 39 | if (clk->parent) | 
|  | 40 | __clk_disable(clk->parent); | 
|  | 41 | } | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | static int __clk_enable(struct clk *clk) | 
|  | 45 | { | 
|  | 46 | int ret = 0; | 
|  | 47 |  | 
|  | 48 | if (clk->refcount++ == 0 && clk->enable) { | 
|  | 49 | if (clk->parent) | 
|  | 50 | ret = __clk_enable(clk->parent); | 
|  | 51 | if (ret) | 
|  | 52 | return ret; | 
|  | 53 | else | 
|  | 54 | return clk->enable(clk); | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | return 0; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | /* This function increments the reference count on the clock and enables the | 
|  | 61 | * clock if not already enabled. The parent clock tree is recursively enabled | 
|  | 62 | */ | 
|  | 63 | int clk_enable(struct clk *clk) | 
|  | 64 | { | 
|  | 65 | int ret = 0; | 
|  | 66 |  | 
|  | 67 | if (!clk) | 
|  | 68 | return -EINVAL; | 
|  | 69 |  | 
|  | 70 | mutex_lock(&clocks_mutex); | 
|  | 71 | ret = __clk_enable(clk); | 
|  | 72 | mutex_unlock(&clocks_mutex); | 
|  | 73 |  | 
|  | 74 | return ret; | 
|  | 75 | } | 
|  | 76 | EXPORT_SYMBOL_GPL(clk_enable); | 
|  | 77 |  | 
|  | 78 | /* This function decrements the reference count on the clock and disables | 
|  | 79 | * the clock when reference count is 0. The parent clock tree is | 
|  | 80 | * recursively disabled | 
|  | 81 | */ | 
|  | 82 | void clk_disable(struct clk *clk) | 
|  | 83 | { | 
|  | 84 | if (!clk) | 
|  | 85 | return; | 
|  | 86 |  | 
|  | 87 | mutex_lock(&clocks_mutex); | 
|  | 88 | __clk_disable(clk); | 
|  | 89 | mutex_unlock(&clocks_mutex); | 
|  | 90 | } | 
|  | 91 | EXPORT_SYMBOL_GPL(clk_disable); | 
|  | 92 |  | 
|  | 93 | /* Retrieve the *current* clock rate. If the clock itself | 
|  | 94 | * does not provide a special calculation routine, ask | 
|  | 95 | * its parent and so on, until one is able to return | 
|  | 96 | * a valid clock rate | 
|  | 97 | */ | 
|  | 98 | unsigned long clk_get_rate(struct clk *clk) | 
|  | 99 | { | 
|  | 100 | if (!clk) | 
|  | 101 | return 0UL; | 
|  | 102 |  | 
|  | 103 | if (clk->get_rate) | 
|  | 104 | return clk->get_rate(clk); | 
|  | 105 |  | 
|  | 106 | return clk_get_rate(clk->parent); | 
|  | 107 | } | 
|  | 108 | EXPORT_SYMBOL_GPL(clk_get_rate); | 
|  | 109 |  | 
|  | 110 | /* Round the requested clock rate to the nearest supported | 
|  | 111 | * rate that is less than or equal to the requested rate. | 
|  | 112 | * This is dependent on the clock's current parent. | 
|  | 113 | */ | 
|  | 114 | long clk_round_rate(struct clk *clk, unsigned long rate) | 
|  | 115 | { | 
|  | 116 | if (!clk) | 
|  | 117 | return 0; | 
|  | 118 | if (!clk->round_rate) | 
|  | 119 | return 0; | 
|  | 120 |  | 
|  | 121 | return clk->round_rate(clk, rate); | 
|  | 122 | } | 
|  | 123 | EXPORT_SYMBOL_GPL(clk_round_rate); | 
|  | 124 |  | 
|  | 125 | /* Set the clock to the requested clock rate. The rate must | 
|  | 126 | * match a supported rate exactly based on what clk_round_rate returns | 
|  | 127 | */ | 
|  | 128 | int clk_set_rate(struct clk *clk, unsigned long rate) | 
|  | 129 | { | 
|  | 130 | int ret = -EINVAL; | 
|  | 131 |  | 
|  | 132 | if (!clk) | 
|  | 133 | return ret; | 
|  | 134 | if (!clk->set_rate || !rate) | 
|  | 135 | return ret; | 
|  | 136 |  | 
|  | 137 | mutex_lock(&clocks_mutex); | 
|  | 138 | ret = clk->set_rate(clk, rate); | 
|  | 139 | mutex_unlock(&clocks_mutex); | 
|  | 140 |  | 
|  | 141 | return ret; | 
|  | 142 | } | 
|  | 143 | EXPORT_SYMBOL_GPL(clk_set_rate); | 
|  | 144 |  | 
|  | 145 | /* Set the clock's parent to another clock source */ | 
|  | 146 | int clk_set_parent(struct clk *clk, struct clk *parent) | 
|  | 147 | { | 
|  | 148 | struct clk *old; | 
|  | 149 | int ret = -EINVAL; | 
|  | 150 |  | 
|  | 151 | if (!clk) | 
|  | 152 | return ret; | 
|  | 153 | if (!clk->set_parent || !parent) | 
|  | 154 | return ret; | 
|  | 155 |  | 
|  | 156 | mutex_lock(&clocks_mutex); | 
|  | 157 | old = clk->parent; | 
|  | 158 | if (clk->refcount) | 
|  | 159 | __clk_enable(parent); | 
|  | 160 | ret = clk->set_parent(clk, parent); | 
|  | 161 | if (ret) | 
|  | 162 | old = parent; | 
|  | 163 | if (clk->refcount) | 
|  | 164 | __clk_disable(old); | 
|  | 165 | mutex_unlock(&clocks_mutex); | 
|  | 166 |  | 
|  | 167 | return ret; | 
|  | 168 | } | 
|  | 169 | EXPORT_SYMBOL_GPL(clk_set_parent); | 
|  | 170 |  | 
|  | 171 | /* Retrieve the clock's parent clock source */ | 
|  | 172 | struct clk *clk_get_parent(struct clk *clk) | 
|  | 173 | { | 
|  | 174 | if (!clk) | 
|  | 175 | return NULL; | 
|  | 176 |  | 
|  | 177 | return clk->parent; | 
|  | 178 | } | 
|  | 179 | EXPORT_SYMBOL_GPL(clk_get_parent); |