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