1 /* 2 * mmp gate clock operation source file 3 * 4 * Copyright (C) 2014 Marvell 5 * Chao Xie <chao.xie@marvell.com> 6 * 7 * This file is licensed under the terms of the GNU General Public 8 * License version 2. This program is licensed "as is" without any 9 * warranty of any kind, whether express or implied. 10 */ 11 12 #include <linux/clk-provider.h> 13 #include <linux/slab.h> 14 #include <linux/io.h> 15 #include <linux/err.h> 16 #include <linux/delay.h> 17 18 #include "clk.h" 19 20 /* 21 * Some clocks will have mutiple bits to enable the clocks, and 22 * the bits to disable the clock is not same as enabling bits. 23 */ 24 25 #define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw) 26 27 static int mmp_clk_gate_enable(struct clk_hw *hw) 28 { 29 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); 30 struct clk *clk = hw->clk; 31 unsigned long flags = 0; 32 unsigned long rate; 33 u32 tmp; 34 35 if (gate->lock) 36 spin_lock_irqsave(gate->lock, flags); 37 38 tmp = readl(gate->reg); 39 tmp &= ~gate->mask; 40 tmp |= gate->val_enable; 41 writel(tmp, gate->reg); 42 43 if (gate->lock) 44 spin_unlock_irqrestore(gate->lock, flags); 45 46 if (gate->flags & MMP_CLK_GATE_NEED_DELAY) { 47 rate = __clk_get_rate(clk); 48 /* Need delay 2 cycles. */ 49 udelay(2000000/rate); 50 } 51 52 return 0; 53 } 54 55 static void mmp_clk_gate_disable(struct clk_hw *hw) 56 { 57 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); 58 unsigned long flags = 0; 59 u32 tmp; 60 61 if (gate->lock) 62 spin_lock_irqsave(gate->lock, flags); 63 64 tmp = readl(gate->reg); 65 tmp &= ~gate->mask; 66 tmp |= gate->val_disable; 67 writel(tmp, gate->reg); 68 69 if (gate->lock) 70 spin_unlock_irqrestore(gate->lock, flags); 71 } 72 73 static int mmp_clk_gate_is_enabled(struct clk_hw *hw) 74 { 75 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); 76 unsigned long flags = 0; 77 u32 tmp; 78 79 if (gate->lock) 80 spin_lock_irqsave(gate->lock, flags); 81 82 tmp = readl(gate->reg); 83 84 if (gate->lock) 85 spin_unlock_irqrestore(gate->lock, flags); 86 87 return (tmp & gate->mask) == gate->val_enable; 88 } 89 90 const struct clk_ops mmp_clk_gate_ops = { 91 .enable = mmp_clk_gate_enable, 92 .disable = mmp_clk_gate_disable, 93 .is_enabled = mmp_clk_gate_is_enabled, 94 }; 95 96 struct clk *mmp_clk_register_gate(struct device *dev, const char *name, 97 const char *parent_name, unsigned long flags, 98 void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable, 99 unsigned int gate_flags, spinlock_t *lock) 100 { 101 struct mmp_clk_gate *gate; 102 struct clk *clk; 103 struct clk_init_data init; 104 105 /* allocate the gate */ 106 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 107 if (!gate) { 108 pr_err("%s:%s could not allocate gate clk\n", __func__, name); 109 return ERR_PTR(-ENOMEM); 110 } 111 112 init.name = name; 113 init.ops = &mmp_clk_gate_ops; 114 init.flags = flags | CLK_IS_BASIC; 115 init.parent_names = (parent_name ? &parent_name : NULL); 116 init.num_parents = (parent_name ? 1 : 0); 117 118 /* struct clk_gate assignments */ 119 gate->reg = reg; 120 gate->mask = mask; 121 gate->val_enable = val_enable; 122 gate->val_disable = val_disable; 123 gate->flags = gate_flags; 124 gate->lock = lock; 125 gate->hw.init = &init; 126 127 clk = clk_register(dev, &gate->hw); 128 129 if (IS_ERR(clk)) 130 kfree(gate); 131 132 return clk; 133 } 134