| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
- */
- #include <linux/module.h>
- #include "vclk.h"
- /* The VCLK gate has a supplementary reset bit to pulse after ungating */
- static inline struct meson_vclk_gate_data *
- clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
- {
- return (struct meson_vclk_gate_data *)clk->data;
- }
- static int meson_vclk_gate_enable(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
- meson_parm_write(clk->map, &vclk->enable, 1);
- /* Do a reset pulse */
- meson_parm_write(clk->map, &vclk->reset, 1);
- meson_parm_write(clk->map, &vclk->reset, 0);
- return 0;
- }
- static void meson_vclk_gate_disable(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
- meson_parm_write(clk->map, &vclk->enable, 0);
- }
- static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
- return meson_parm_read(clk->map, &vclk->enable);
- }
- const struct clk_ops meson_vclk_gate_ops = {
- .enable = meson_vclk_gate_enable,
- .disable = meson_vclk_gate_disable,
- .is_enabled = meson_vclk_gate_is_enabled,
- };
- EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, CLK_MESON);
- /* The VCLK Divider has supplementary reset & enable bits */
- static inline struct meson_vclk_div_data *
- clk_get_meson_vclk_div_data(struct clk_regmap *clk)
- {
- return (struct meson_vclk_div_data *)clk->data;
- }
- static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
- unsigned long prate)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div),
- vclk->table, vclk->flags, vclk->div.width);
- }
- static int meson_vclk_div_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
- vclk->flags);
- }
- static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- int ret;
- ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
- vclk->flags);
- if (ret < 0)
- return ret;
- meson_parm_write(clk->map, &vclk->div, ret);
- return 0;
- };
- static int meson_vclk_div_enable(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- /* Unreset the divider when ungating */
- meson_parm_write(clk->map, &vclk->reset, 0);
- meson_parm_write(clk->map, &vclk->enable, 1);
- return 0;
- }
- static void meson_vclk_div_disable(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- /* Reset the divider when gating */
- meson_parm_write(clk->map, &vclk->enable, 0);
- meson_parm_write(clk->map, &vclk->reset, 1);
- }
- static int meson_vclk_div_is_enabled(struct clk_hw *hw)
- {
- struct clk_regmap *clk = to_clk_regmap(hw);
- struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
- return meson_parm_read(clk->map, &vclk->enable);
- }
- const struct clk_ops meson_vclk_div_ops = {
- .recalc_rate = meson_vclk_div_recalc_rate,
- .determine_rate = meson_vclk_div_determine_rate,
- .set_rate = meson_vclk_div_set_rate,
- .enable = meson_vclk_div_enable,
- .disable = meson_vclk_div_disable,
- .is_enabled = meson_vclk_div_is_enabled,
- };
- EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, CLK_MESON);
- MODULE_DESCRIPTION("Amlogic vclk clock driver");
- MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
- MODULE_LICENSE("GPL");
- MODULE_IMPORT_NS(CLK_MESON);
|