Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2018 BayLibre, SAS.
0004  * Author: Jerome Brunet <jbrunet@baylibre.com>
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         /* Gives a hint that something is wrong */
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     /* if read only, just return current value */
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 /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
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");