1/* 2 * Top-level clock management API 3 * see include/linux/clk.h for description. 4 * These routines are hardware-independent, 5 * and all hardware-specific code is invoked 6 * through the "ops" methods. 7 */ 8#include <linux/module.h> 9#include <linux/kernel.h> 10#include <linux/errno.h> 11#include <linux/clk.h> 12#include <linux/mutex.h> 13 14#include <mach/clkdev.h> 15 16int clk_enable(struct clk *clk) 17{ 18 int ret ; 19 20 ret = atomic_inc_return( &clk->ena_cnt ); 21 if( ret > 1 ) 22 return 0; 23 /* Continue of count was moved from 0 to 1 - reentrant */ 24 if( clk->parent ) 25 ret = clk_enable( clk->parent ); 26 else 27 ret = 0; 28 29 if( ret == 0 ) 30 { 31 if( ! clk->ops || ! clk->ops->enable ) 32 { 33 if( clk->rate ) 34 ret = 0 ; 35 else 36 ret = -EIO; 37 } 38 else 39 { 40 ret = clk->ops->enable( clk ) ; 41 } 42 } 43 44 if( ret != 0 ) 45 atomic_dec( &clk->ena_cnt ); 46 47 return ret ; 48} 49EXPORT_SYMBOL(clk_enable); 50 51void clk_disable(struct clk *clk) 52{ 53 int ret ; 54 55 ret = atomic_dec_return( &clk->ena_cnt ); 56 57 /* Continue if this is the last client to disable - reentrant */ 58 if( ret > 0 ) 59 return ; 60 BUG_ON( ret < 0 ); 61 62 if( ! clk->ops || ! clk->ops->disable ) 63 return; 64 65 clk->ops->disable( clk ); 66 67 if( clk->parent ) 68 clk_disable( clk->parent ); 69 70 return ; 71} 72EXPORT_SYMBOL(clk_disable); 73 74unsigned long clk_get_rate(struct clk *clk) 75{ 76 /* Recurse to update parent's frequency */ 77 if( clk->parent ) 78 clk_get_rate( clk->parent ); 79 /* Read hardware registers if needed */ 80 if( clk->ops && clk->ops->status ) 81 clk->ops->status(clk); 82 return clk->rate; 83} 84EXPORT_SYMBOL(clk_get_rate); 85 86long clk_round_rate(struct clk *clk, unsigned long rate) 87{ 88 long ret = -EIO; 89 if (clk->ops && clk->ops->round) 90 ret = clk->ops->round(clk, rate); 91 return ret; 92} 93EXPORT_SYMBOL(clk_round_rate); 94 95int clk_set_rate(struct clk *clk, unsigned long rate) 96{ 97 int ret = -EIO; 98 99 if( rate == clk->rate ) 100 return 0; 101 102 if (clk->ops && clk->ops->setrate) 103 ret = clk->ops->setrate(clk, rate); 104 105 return ret; 106} 107EXPORT_SYMBOL(clk_set_rate); 108 109/* 110 * clk_get(), clk_put() are implemented in arch/arm/common/clock.c 111 * but it needs these two stub functions for platform-specific operations. 112 * Reeturn 1 on success 0 on failure. 113 */ 114 115int __clk_get(struct clk *clk) 116{ 117 int ret ; 118 119 ret = atomic_inc_return( &clk->use_cnt ); 120 if( ret > 1 ) 121 return 1; 122 if( clk->parent ) 123 return __clk_get( clk->parent ); 124 return 1; 125} 126 127void __clk_put(struct clk *clk) 128{ 129 int ret; 130 131 ret = atomic_dec_return( &clk->use_cnt ); 132 if( ret > 0 ) 133 return; 134 135 BUG_ON( ret < 0 ); 136 137 if( clk->parent ) 138 __clk_put( clk->parent ); 139} 140