123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /*
- * mmp gate clock operation source file
- *
- * Copyright (C) 2014 Marvell
- * Chao Xie <[email protected]>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
- #include <linux/clk-provider.h>
- #include <linux/slab.h>
- #include <linux/io.h>
- #include <linux/err.h>
- #include <linux/delay.h>
- #include "clk.h"
- /*
- * Some clocks will have mutiple bits to enable the clocks, and
- * the bits to disable the clock is not same as enabling bits.
- */
- #define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw)
- static int mmp_clk_gate_enable(struct clk_hw *hw)
- {
- struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
- unsigned long flags = 0;
- unsigned long rate;
- u32 tmp;
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- tmp = readl(gate->reg);
- tmp &= ~gate->mask;
- tmp |= gate->val_enable;
- writel(tmp, gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
- if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
- rate = clk_hw_get_rate(hw);
- /* Need delay 2 cycles. */
- udelay(2000000/rate);
- }
- return 0;
- }
- static void mmp_clk_gate_disable(struct clk_hw *hw)
- {
- struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
- unsigned long flags = 0;
- u32 tmp;
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- tmp = readl(gate->reg);
- tmp &= ~gate->mask;
- tmp |= gate->val_disable;
- writel(tmp, gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
- }
- static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
- {
- struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
- unsigned long flags = 0;
- u32 tmp;
- if (gate->lock)
- spin_lock_irqsave(gate->lock, flags);
- tmp = readl(gate->reg);
- if (gate->lock)
- spin_unlock_irqrestore(gate->lock, flags);
- return (tmp & gate->mask) == gate->val_enable;
- }
- const struct clk_ops mmp_clk_gate_ops = {
- .enable = mmp_clk_gate_enable,
- .disable = mmp_clk_gate_disable,
- .is_enabled = mmp_clk_gate_is_enabled,
- };
- struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
- const char *parent_name, unsigned long flags,
- void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
- unsigned int gate_flags, spinlock_t *lock)
- {
- struct mmp_clk_gate *gate;
- struct clk *clk;
- struct clk_init_data init;
- /* allocate the gate */
- gate = kzalloc(sizeof(*gate), GFP_KERNEL);
- if (!gate) {
- pr_err("%s:%s could not allocate gate clk\n", __func__, name);
- return ERR_PTR(-ENOMEM);
- }
- init.name = name;
- init.ops = &mmp_clk_gate_ops;
- init.flags = flags | CLK_IS_BASIC;
- init.parent_names = (parent_name ? &parent_name : NULL);
- init.num_parents = (parent_name ? 1 : 0);
- /* struct clk_gate assignments */
- gate->reg = reg;
- gate->mask = mask;
- gate->val_enable = val_enable;
- gate->val_disable = val_disable;
- gate->flags = gate_flags;
- gate->lock = lock;
- gate->hw.init = &init;
- clk = clk_register(dev, &gate->hw);
- if (IS_ERR(clk))
- kfree(gate);
- return clk;
- }
|