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 unsigned long flags = 0; 31 unsigned long rate; 32 u32 tmp; 33 34 if (gate->lock) 35 spin_lock_irqsave(gate->lock, flags); 36 37 tmp = readl(gate->reg); 38 tmp &= ~gate->mask; 39 tmp |= gate->val_enable; 40 writel(tmp, gate->reg); 41 42 if (gate->lock) 43 spin_unlock_irqrestore(gate->lock, flags); 44 45 if (gate->flags & MMP_CLK_GATE_NEED_DELAY) { 46 rate = clk_hw_get_rate(hw); 47 /* Need delay 2 cycles. */ 48 udelay(2000000/rate); 49 } 50 51 return 0; 52 } 53 54 static void mmp_clk_gate_disable(struct clk_hw *hw) 55 { 56 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); 57 unsigned long flags = 0; 58 u32 tmp; 59 60 if (gate->lock) 61 spin_lock_irqsave(gate->lock, flags); 62 63 tmp = readl(gate->reg); 64 tmp &= ~gate->mask; 65 tmp |= gate->val_disable; 66 writel(tmp, gate->reg); 67 68 if (gate->lock) 69 spin_unlock_irqrestore(gate->lock, flags); 70 } 71 72 static int mmp_clk_gate_is_enabled(struct clk_hw *hw) 73 { 74 struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); 75 unsigned long flags = 0; 76 u32 tmp; 77 78 if (gate->lock) 79 spin_lock_irqsave(gate->lock, flags); 80 81 tmp = readl(gate->reg); 82 83 if (gate->lock) 84 spin_unlock_irqrestore(gate->lock, flags); 85 86 return (tmp & gate->mask) == gate->val_enable; 87 } 88 89 const struct clk_ops mmp_clk_gate_ops = { 90 .enable = mmp_clk_gate_enable, 91 .disable = mmp_clk_gate_disable, 92 .is_enabled = mmp_clk_gate_is_enabled, 93 }; 94 95 struct clk *mmp_clk_register_gate(struct device *dev, const char *name, 96 const char *parent_name, unsigned long flags, 97 void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable, 98 unsigned int gate_flags, spinlock_t *lock) 99 { 100 struct mmp_clk_gate *gate; 101 struct clk *clk; 102 struct clk_init_data init; 103 104 /* allocate the gate */ 105 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 106 if (!gate) 107 return ERR_PTR(-ENOMEM); 108 109 init.name = name; 110 init.ops = &mmp_clk_gate_ops; 111 init.flags = flags | CLK_IS_BASIC; 112 init.parent_names = (parent_name ? &parent_name : NULL); 113 init.num_parents = (parent_name ? 1 : 0); 114 115 /* struct clk_gate assignments */ 116 gate->reg = reg; 117 gate->mask = mask; 118 gate->val_enable = val_enable; 119 gate->val_disable = val_disable; 120 gate->flags = gate_flags; 121 gate->lock = lock; 122 gate->hw.init = &init; 123 124 clk = clk_register(dev, &gate->hw); 125 126 if (IS_ERR(clk)) 127 kfree(gate); 128 129 return clk; 130 } 131