128 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mmp gate clock operation source file4 *5 * Copyright (C) 2014 Marvell6 * 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, and19 * 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 24static 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 51static 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 69static 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 86const 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 92struct 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