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