1/***************************************************************************/ 2 3/* 4 * clk.c -- general ColdFire CPU kernel clk handling 5 * 6 * Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com) 7 */ 8 9/***************************************************************************/ 10 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/platform_device.h> 14#include <linux/mutex.h> 15#include <linux/clk.h> 16#include <linux/io.h> 17#include <linux/err.h> 18#include <asm/coldfire.h> 19#include <asm/mcfsim.h> 20#include <asm/mcfclk.h> 21 22static DEFINE_SPINLOCK(clk_lock); 23 24#ifdef MCFPM_PPMCR0 25/* 26 * For more advanced ColdFire parts that have clocks that can be enabled 27 * we supply enable/disable functions. These must properly define their 28 * clocks in their platform specific code. 29 */ 30void __clk_init_enabled(struct clk *clk) 31{ 32 clk->enabled = 1; 33 clk->clk_ops->enable(clk); 34} 35 36void __clk_init_disabled(struct clk *clk) 37{ 38 clk->enabled = 0; 39 clk->clk_ops->disable(clk); 40} 41 42static void __clk_enable0(struct clk *clk) 43{ 44 __raw_writeb(clk->slot, MCFPM_PPMCR0); 45} 46 47static void __clk_disable0(struct clk *clk) 48{ 49 __raw_writeb(clk->slot, MCFPM_PPMSR0); 50} 51 52struct clk_ops clk_ops0 = { 53 .enable = __clk_enable0, 54 .disable = __clk_disable0, 55}; 56 57#ifdef MCFPM_PPMCR1 58static void __clk_enable1(struct clk *clk) 59{ 60 __raw_writeb(clk->slot, MCFPM_PPMCR1); 61} 62 63static void __clk_disable1(struct clk *clk) 64{ 65 __raw_writeb(clk->slot, MCFPM_PPMSR1); 66} 67 68struct clk_ops clk_ops1 = { 69 .enable = __clk_enable1, 70 .disable = __clk_disable1, 71}; 72#endif /* MCFPM_PPMCR1 */ 73#endif /* MCFPM_PPMCR0 */ 74 75struct clk *clk_get(struct device *dev, const char *id) 76{ 77 const char *clk_name = dev ? dev_name(dev) : id ? id : NULL; 78 struct clk *clk; 79 unsigned i; 80 81 for (i = 0; (clk = mcf_clks[i]) != NULL; ++i) 82 if (!strcmp(clk->name, clk_name)) 83 return clk; 84 pr_warn("clk_get: didn't find clock %s\n", clk_name); 85 return ERR_PTR(-ENOENT); 86} 87EXPORT_SYMBOL(clk_get); 88 89int clk_enable(struct clk *clk) 90{ 91 unsigned long flags; 92 spin_lock_irqsave(&clk_lock, flags); 93 if ((clk->enabled++ == 0) && clk->clk_ops) 94 clk->clk_ops->enable(clk); 95 spin_unlock_irqrestore(&clk_lock, flags); 96 97 return 0; 98} 99EXPORT_SYMBOL(clk_enable); 100 101void clk_disable(struct clk *clk) 102{ 103 unsigned long flags; 104 spin_lock_irqsave(&clk_lock, flags); 105 if ((--clk->enabled == 0) && clk->clk_ops) 106 clk->clk_ops->disable(clk); 107 spin_unlock_irqrestore(&clk_lock, flags); 108} 109EXPORT_SYMBOL(clk_disable); 110 111void clk_put(struct clk *clk) 112{ 113 if (clk->enabled != 0) 114 pr_warn("clk_put %s still enabled\n", clk->name); 115} 116EXPORT_SYMBOL(clk_put); 117 118unsigned long clk_get_rate(struct clk *clk) 119{ 120 return clk->rate; 121} 122EXPORT_SYMBOL(clk_get_rate); 123 124/***************************************************************************/ 125