123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2018 BayLibre, SAS.
- * Author: Jerome Brunet <[email protected]>
- */
- #include <linux/module.h>
- #include "clk-regmap.h"
- static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
- int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
- set ^= enable;
- return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx),
- set ? BIT(gate->bit_idx) : 0);
- }
- static int clk_regmap_gate_enable(struct clk_hw *hw)
- {
- return clk_regmap_gate_endisable(hw, 1);
- }
- static void clk_regmap_gate_disable(struct clk_hw *hw)
- {
- clk_regmap_gate_endisable(hw, 0);
- }
- static int clk_regmap_gate_is_enabled(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
- unsigned int val;
- regmap_read(clk->map, gate->offset, &val);
- if (gate->flags & CLK_GATE_SET_TO_DISABLE)
- val ^= BIT(gate->bit_idx);
- val &= BIT(gate->bit_idx);
- return val ? 1 : 0;
- }
- const struct clk_ops clk_regmap_gate_ops = {
- .enable = clk_regmap_gate_enable,
- .disable = clk_regmap_gate_disable,
- .is_enabled = clk_regmap_gate_is_enabled,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_gate_ops);
- const struct clk_ops clk_regmap_gate_ro_ops = {
- .is_enabled = clk_regmap_gate_is_enabled,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops);
- static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
- unsigned int val;
- int ret;
- ret = regmap_read(clk->map, div->offset, &val);
- if (ret)
- /* Gives a hint that something is wrong */
- return 0;
- val >>= div->shift;
- val &= clk_div_mask(div->width);
- return divider_recalc_rate(hw, prate, val, div->table, div->flags,
- div->width);
- }
- static int clk_regmap_div_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
- unsigned int val;
- int ret;
- /* if read only, just return current value */
- if (div->flags & CLK_DIVIDER_READ_ONLY) {
- ret = regmap_read(clk->map, div->offset, &val);
- if (ret)
- return ret;
- val >>= div->shift;
- val &= clk_div_mask(div->width);
- return divider_ro_determine_rate(hw, req, div->table,
- div->width, div->flags, val);
- }
- return divider_determine_rate(hw, req, div->table, div->width,
- div->flags);
- }
- static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
- unsigned int val;
- int ret;
- ret = divider_get_val(rate, parent_rate, div->table, div->width,
- div->flags);
- if (ret < 0)
- return ret;
- val = (unsigned int)ret << div->shift;
- return regmap_update_bits(clk->map, div->offset,
- clk_div_mask(div->width) << div->shift, val);
- };
- /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
- const struct clk_ops clk_regmap_divider_ops = {
- .recalc_rate = clk_regmap_div_recalc_rate,
- .determine_rate = clk_regmap_div_determine_rate,
- .set_rate = clk_regmap_div_set_rate,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
- const struct clk_ops clk_regmap_divider_ro_ops = {
- .recalc_rate = clk_regmap_div_recalc_rate,
- .determine_rate = clk_regmap_div_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
- static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
- unsigned int val;
- int ret;
- ret = regmap_read(clk->map, mux->offset, &val);
- if (ret)
- return ret;
- val >>= mux->shift;
- val &= mux->mask;
- return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
- }
- static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
- unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index);
- return regmap_update_bits(clk->map, mux->offset,
- mux->mask << mux->shift,
- val << mux->shift);
- }
- static int clk_regmap_mux_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
- return clk_mux_determine_rate_flags(hw, req, mux->flags);
- }
- const struct clk_ops clk_regmap_mux_ops = {
- .get_parent = clk_regmap_mux_get_parent,
- .set_parent = clk_regmap_mux_set_parent,
- .determine_rate = clk_regmap_mux_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_mux_ops);
- const struct clk_ops clk_regmap_mux_ro_ops = {
- .get_parent = clk_regmap_mux_get_parent,
- };
- EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
- MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
- MODULE_AUTHOR("Jerome Brunet <[email protected]>");
- MODULE_LICENSE("GPL v2");
|