0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/clk-provider.h>
0008 #include <linux/export.h>
0009 #include <linux/slab.h>
0010 #include <linux/err.h>
0011
0012 #include "clk.h"
0013
0014 static u8 clk_periph_get_parent(struct clk_hw *hw)
0015 {
0016 struct tegra_clk_periph *periph = to_clk_periph(hw);
0017 const struct clk_ops *mux_ops = periph->mux_ops;
0018 struct clk_hw *mux_hw = &periph->mux.hw;
0019
0020 __clk_hw_set_clk(mux_hw, hw);
0021
0022 return mux_ops->get_parent(mux_hw);
0023 }
0024
0025 static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
0026 {
0027 struct tegra_clk_periph *periph = to_clk_periph(hw);
0028 const struct clk_ops *mux_ops = periph->mux_ops;
0029 struct clk_hw *mux_hw = &periph->mux.hw;
0030
0031 __clk_hw_set_clk(mux_hw, hw);
0032
0033 return mux_ops->set_parent(mux_hw, index);
0034 }
0035
0036 static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
0037 unsigned long parent_rate)
0038 {
0039 struct tegra_clk_periph *periph = to_clk_periph(hw);
0040 const struct clk_ops *div_ops = periph->div_ops;
0041 struct clk_hw *div_hw = &periph->divider.hw;
0042
0043 __clk_hw_set_clk(div_hw, hw);
0044
0045 return div_ops->recalc_rate(div_hw, parent_rate);
0046 }
0047
0048 static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
0049 unsigned long *prate)
0050 {
0051 struct tegra_clk_periph *periph = to_clk_periph(hw);
0052 const struct clk_ops *div_ops = periph->div_ops;
0053 struct clk_hw *div_hw = &periph->divider.hw;
0054
0055 __clk_hw_set_clk(div_hw, hw);
0056
0057 return div_ops->round_rate(div_hw, rate, prate);
0058 }
0059
0060 static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
0061 unsigned long parent_rate)
0062 {
0063 struct tegra_clk_periph *periph = to_clk_periph(hw);
0064 const struct clk_ops *div_ops = periph->div_ops;
0065 struct clk_hw *div_hw = &periph->divider.hw;
0066
0067 __clk_hw_set_clk(div_hw, hw);
0068
0069 return div_ops->set_rate(div_hw, rate, parent_rate);
0070 }
0071
0072 static int clk_periph_is_enabled(struct clk_hw *hw)
0073 {
0074 struct tegra_clk_periph *periph = to_clk_periph(hw);
0075 const struct clk_ops *gate_ops = periph->gate_ops;
0076 struct clk_hw *gate_hw = &periph->gate.hw;
0077
0078 __clk_hw_set_clk(gate_hw, hw);
0079
0080 return gate_ops->is_enabled(gate_hw);
0081 }
0082
0083 static int clk_periph_enable(struct clk_hw *hw)
0084 {
0085 struct tegra_clk_periph *periph = to_clk_periph(hw);
0086 const struct clk_ops *gate_ops = periph->gate_ops;
0087 struct clk_hw *gate_hw = &periph->gate.hw;
0088
0089 __clk_hw_set_clk(gate_hw, hw);
0090
0091 return gate_ops->enable(gate_hw);
0092 }
0093
0094 static void clk_periph_disable(struct clk_hw *hw)
0095 {
0096 struct tegra_clk_periph *periph = to_clk_periph(hw);
0097 const struct clk_ops *gate_ops = periph->gate_ops;
0098 struct clk_hw *gate_hw = &periph->gate.hw;
0099
0100 gate_ops->disable(gate_hw);
0101 }
0102
0103 static void clk_periph_disable_unused(struct clk_hw *hw)
0104 {
0105 struct tegra_clk_periph *periph = to_clk_periph(hw);
0106 const struct clk_ops *gate_ops = periph->gate_ops;
0107 struct clk_hw *gate_hw = &periph->gate.hw;
0108
0109 gate_ops->disable_unused(gate_hw);
0110 }
0111
0112 static void clk_periph_restore_context(struct clk_hw *hw)
0113 {
0114 struct tegra_clk_periph *periph = to_clk_periph(hw);
0115 const struct clk_ops *div_ops = periph->div_ops;
0116 struct clk_hw *div_hw = &periph->divider.hw;
0117 int parent_id;
0118
0119 parent_id = clk_hw_get_parent_index(hw);
0120 if (WARN_ON(parent_id < 0))
0121 return;
0122
0123 if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
0124 div_ops->restore_context(div_hw);
0125
0126 clk_periph_set_parent(hw, parent_id);
0127 }
0128
0129 const struct clk_ops tegra_clk_periph_ops = {
0130 .get_parent = clk_periph_get_parent,
0131 .set_parent = clk_periph_set_parent,
0132 .recalc_rate = clk_periph_recalc_rate,
0133 .round_rate = clk_periph_round_rate,
0134 .set_rate = clk_periph_set_rate,
0135 .is_enabled = clk_periph_is_enabled,
0136 .enable = clk_periph_enable,
0137 .disable = clk_periph_disable,
0138 .disable_unused = clk_periph_disable_unused,
0139 .restore_context = clk_periph_restore_context,
0140 };
0141
0142 static const struct clk_ops tegra_clk_periph_nodiv_ops = {
0143 .get_parent = clk_periph_get_parent,
0144 .set_parent = clk_periph_set_parent,
0145 .is_enabled = clk_periph_is_enabled,
0146 .enable = clk_periph_enable,
0147 .disable = clk_periph_disable,
0148 .disable_unused = clk_periph_disable_unused,
0149 .restore_context = clk_periph_restore_context,
0150 };
0151
0152 static const struct clk_ops tegra_clk_periph_no_gate_ops = {
0153 .get_parent = clk_periph_get_parent,
0154 .set_parent = clk_periph_set_parent,
0155 .recalc_rate = clk_periph_recalc_rate,
0156 .round_rate = clk_periph_round_rate,
0157 .set_rate = clk_periph_set_rate,
0158 .restore_context = clk_periph_restore_context,
0159 };
0160
0161 static struct clk *_tegra_clk_register_periph(const char *name,
0162 const char * const *parent_names, int num_parents,
0163 struct tegra_clk_periph *periph,
0164 void __iomem *clk_base, u32 offset,
0165 unsigned long flags)
0166 {
0167 struct clk *clk;
0168 struct clk_init_data init;
0169 const struct tegra_clk_periph_regs *bank;
0170 bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV);
0171
0172 if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) {
0173 flags |= CLK_SET_RATE_PARENT;
0174 init.ops = &tegra_clk_periph_nodiv_ops;
0175 } else if (periph->gate.flags & TEGRA_PERIPH_NO_GATE)
0176 init.ops = &tegra_clk_periph_no_gate_ops;
0177 else
0178 init.ops = &tegra_clk_periph_ops;
0179
0180 init.name = name;
0181 init.flags = flags;
0182 init.parent_names = parent_names;
0183 init.num_parents = num_parents;
0184
0185 bank = get_reg_bank(periph->gate.clk_num);
0186 if (!bank)
0187 return ERR_PTR(-EINVAL);
0188
0189
0190 periph->hw.init = &init;
0191 periph->magic = TEGRA_CLK_PERIPH_MAGIC;
0192 periph->mux.reg = clk_base + offset;
0193 periph->divider.reg = div ? (clk_base + offset) : NULL;
0194 periph->gate.clk_base = clk_base;
0195 periph->gate.regs = bank;
0196 periph->gate.enable_refcnt = periph_clk_enb_refcnt;
0197
0198 clk = clk_register(NULL, &periph->hw);
0199 if (IS_ERR(clk))
0200 return clk;
0201
0202 periph->mux.hw.clk = clk;
0203 periph->divider.hw.clk = div ? clk : NULL;
0204 periph->gate.hw.clk = clk;
0205
0206 return clk;
0207 }
0208
0209 struct clk *tegra_clk_register_periph(const char *name,
0210 const char * const *parent_names, int num_parents,
0211 struct tegra_clk_periph *periph, void __iomem *clk_base,
0212 u32 offset, unsigned long flags)
0213 {
0214 return _tegra_clk_register_periph(name, parent_names, num_parents,
0215 periph, clk_base, offset, flags);
0216 }
0217
0218 struct clk *tegra_clk_register_periph_nodiv(const char *name,
0219 const char * const *parent_names, int num_parents,
0220 struct tegra_clk_periph *periph, void __iomem *clk_base,
0221 u32 offset)
0222 {
0223 periph->gate.flags |= TEGRA_PERIPH_NO_DIV;
0224 return _tegra_clk_register_periph(name, parent_names, num_parents,
0225 periph, clk_base, offset, CLK_SET_RATE_PARENT);
0226 }
0227
0228 struct clk *tegra_clk_register_periph_data(void __iomem *clk_base,
0229 struct tegra_periph_init_data *init)
0230 {
0231 return _tegra_clk_register_periph(init->name, init->p.parent_names,
0232 init->num_parents, &init->periph,
0233 clk_base, init->offset, init->flags);
0234 }