0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include "clk-regmap.h"
0009
0010 static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
0011 {
0012 struct clk_regmap *clk = to_clk_regmap(hw);
0013 struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
0014 int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
0015
0016 set ^= enable;
0017
0018 return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx),
0019 set ? BIT(gate->bit_idx) : 0);
0020 }
0021
0022 static int clk_regmap_gate_enable(struct clk_hw *hw)
0023 {
0024 return clk_regmap_gate_endisable(hw, 1);
0025 }
0026
0027 static void clk_regmap_gate_disable(struct clk_hw *hw)
0028 {
0029 clk_regmap_gate_endisable(hw, 0);
0030 }
0031
0032 static int clk_regmap_gate_is_enabled(struct clk_hw *hw)
0033 {
0034 struct clk_regmap *clk = to_clk_regmap(hw);
0035 struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
0036 unsigned int val;
0037
0038 regmap_read(clk->map, gate->offset, &val);
0039 if (gate->flags & CLK_GATE_SET_TO_DISABLE)
0040 val ^= BIT(gate->bit_idx);
0041
0042 val &= BIT(gate->bit_idx);
0043
0044 return val ? 1 : 0;
0045 }
0046
0047 const struct clk_ops clk_regmap_gate_ops = {
0048 .enable = clk_regmap_gate_enable,
0049 .disable = clk_regmap_gate_disable,
0050 .is_enabled = clk_regmap_gate_is_enabled,
0051 };
0052 EXPORT_SYMBOL_GPL(clk_regmap_gate_ops);
0053
0054 const struct clk_ops clk_regmap_gate_ro_ops = {
0055 .is_enabled = clk_regmap_gate_is_enabled,
0056 };
0057 EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops);
0058
0059 static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
0060 unsigned long prate)
0061 {
0062 struct clk_regmap *clk = to_clk_regmap(hw);
0063 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
0064 unsigned int val;
0065 int ret;
0066
0067 ret = regmap_read(clk->map, div->offset, &val);
0068 if (ret)
0069
0070 return 0;
0071
0072 val >>= div->shift;
0073 val &= clk_div_mask(div->width);
0074 return divider_recalc_rate(hw, prate, val, div->table, div->flags,
0075 div->width);
0076 }
0077
0078 static int clk_regmap_div_determine_rate(struct clk_hw *hw,
0079 struct clk_rate_request *req)
0080 {
0081 struct clk_regmap *clk = to_clk_regmap(hw);
0082 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
0083 unsigned int val;
0084 int ret;
0085
0086
0087 if (div->flags & CLK_DIVIDER_READ_ONLY) {
0088 ret = regmap_read(clk->map, div->offset, &val);
0089 if (ret)
0090 return ret;
0091
0092 val >>= div->shift;
0093 val &= clk_div_mask(div->width);
0094
0095 return divider_ro_determine_rate(hw, req, div->table,
0096 div->width, div->flags, val);
0097 }
0098
0099 return divider_determine_rate(hw, req, div->table, div->width,
0100 div->flags);
0101 }
0102
0103 static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
0104 unsigned long parent_rate)
0105 {
0106 struct clk_regmap *clk = to_clk_regmap(hw);
0107 struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
0108 unsigned int val;
0109 int ret;
0110
0111 ret = divider_get_val(rate, parent_rate, div->table, div->width,
0112 div->flags);
0113 if (ret < 0)
0114 return ret;
0115
0116 val = (unsigned int)ret << div->shift;
0117 return regmap_update_bits(clk->map, div->offset,
0118 clk_div_mask(div->width) << div->shift, val);
0119 };
0120
0121
0122
0123 const struct clk_ops clk_regmap_divider_ops = {
0124 .recalc_rate = clk_regmap_div_recalc_rate,
0125 .determine_rate = clk_regmap_div_determine_rate,
0126 .set_rate = clk_regmap_div_set_rate,
0127 };
0128 EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
0129
0130 const struct clk_ops clk_regmap_divider_ro_ops = {
0131 .recalc_rate = clk_regmap_div_recalc_rate,
0132 .determine_rate = clk_regmap_div_determine_rate,
0133 };
0134 EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
0135
0136 static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
0137 {
0138 struct clk_regmap *clk = to_clk_regmap(hw);
0139 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
0140 unsigned int val;
0141 int ret;
0142
0143 ret = regmap_read(clk->map, mux->offset, &val);
0144 if (ret)
0145 return ret;
0146
0147 val >>= mux->shift;
0148 val &= mux->mask;
0149 return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
0150 }
0151
0152 static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
0153 {
0154 struct clk_regmap *clk = to_clk_regmap(hw);
0155 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
0156 unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index);
0157
0158 return regmap_update_bits(clk->map, mux->offset,
0159 mux->mask << mux->shift,
0160 val << mux->shift);
0161 }
0162
0163 static int clk_regmap_mux_determine_rate(struct clk_hw *hw,
0164 struct clk_rate_request *req)
0165 {
0166 struct clk_regmap *clk = to_clk_regmap(hw);
0167 struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
0168
0169 return clk_mux_determine_rate_flags(hw, req, mux->flags);
0170 }
0171
0172 const struct clk_ops clk_regmap_mux_ops = {
0173 .get_parent = clk_regmap_mux_get_parent,
0174 .set_parent = clk_regmap_mux_set_parent,
0175 .determine_rate = clk_regmap_mux_determine_rate,
0176 };
0177 EXPORT_SYMBOL_GPL(clk_regmap_mux_ops);
0178
0179 const struct clk_ops clk_regmap_mux_ro_ops = {
0180 .get_parent = clk_regmap_mux_get_parent,
0181 };
0182 EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
0183
0184 MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
0185 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0186 MODULE_LICENSE("GPL v2");