File Index
Files and directories
Sign in
FILE

vclk.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/meson/vclk.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
  4 */
  5
  6#include <linux/module.h>
  7#include "vclk.h"
  8
  9/* The VCLK gate has a supplementary reset bit to pulse after ungating */
 10
 11static inline struct meson_vclk_gate_data *
 12clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
 13{
 14	return (struct meson_vclk_gate_data *)clk->data;
 15}
 16
 17static int meson_vclk_gate_enable(struct clk_hw *hw)
 18{
 19	struct clk_regmap *clk = to_clk_regmap(hw);
 20	struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
 21
 22	meson_parm_write(clk->map, &vclk->enable, 1);
 23
 24	/* Do a reset pulse */
 25	meson_parm_write(clk->map, &vclk->reset, 1);
 26	meson_parm_write(clk->map, &vclk->reset, 0);
 27
 28	return 0;
 29}
 30
 31static void meson_vclk_gate_disable(struct clk_hw *hw)
 32{
 33	struct clk_regmap *clk = to_clk_regmap(hw);
 34	struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
 35
 36	meson_parm_write(clk->map, &vclk->enable, 0);
 37}
 38
 39static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
 40{
 41	struct clk_regmap *clk = to_clk_regmap(hw);
 42	struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
 43
 44	return meson_parm_read(clk->map, &vclk->enable);
 45}
 46
 47const struct clk_ops meson_vclk_gate_ops = {
 48	.init = clk_regmap_init,
 49	.enable = meson_vclk_gate_enable,
 50	.disable = meson_vclk_gate_disable,
 51	.is_enabled = meson_vclk_gate_is_enabled,
 52};
 53EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, "CLK_MESON");
 54
 55/* The VCLK Divider has supplementary reset & enable bits */
 56
 57static inline struct meson_vclk_div_data *
 58clk_get_meson_vclk_div_data(struct clk_regmap *clk)
 59{
 60	return (struct meson_vclk_div_data *)clk->data;
 61}
 62
 63static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
 64						unsigned long prate)
 65{
 66	struct clk_regmap *clk = to_clk_regmap(hw);
 67	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 68
 69	return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div),
 70				   vclk->table, vclk->flags, vclk->div.width);
 71}
 72
 73static int meson_vclk_div_determine_rate(struct clk_hw *hw,
 74					 struct clk_rate_request *req)
 75{
 76	struct clk_regmap *clk = to_clk_regmap(hw);
 77	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 78
 79	return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
 80				      vclk->flags);
 81}
 82
 83static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
 84				   unsigned long parent_rate)
 85{
 86	struct clk_regmap *clk = to_clk_regmap(hw);
 87	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 88	int ret;
 89
 90	ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
 91			      vclk->flags);
 92	if (ret < 0)
 93		return ret;
 94
 95	meson_parm_write(clk->map, &vclk->div, ret);
 96
 97	return 0;
 98};
 99
100static int meson_vclk_div_enable(struct clk_hw *hw)
101{
102	struct clk_regmap *clk = to_clk_regmap(hw);
103	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
104
105	/* Unreset the divider when ungating */
106	meson_parm_write(clk->map, &vclk->reset, 0);
107	meson_parm_write(clk->map, &vclk->enable, 1);
108
109	return 0;
110}
111
112static void meson_vclk_div_disable(struct clk_hw *hw)
113{
114	struct clk_regmap *clk = to_clk_regmap(hw);
115	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
116
117	/* Reset the divider when gating */
118	meson_parm_write(clk->map, &vclk->enable, 0);
119	meson_parm_write(clk->map, &vclk->reset, 1);
120}
121
122static int meson_vclk_div_is_enabled(struct clk_hw *hw)
123{
124	struct clk_regmap *clk = to_clk_regmap(hw);
125	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
126
127	return meson_parm_read(clk->map, &vclk->enable);
128}
129
130const struct clk_ops meson_vclk_div_ops = {
131	.init = clk_regmap_init,
132	.recalc_rate = meson_vclk_div_recalc_rate,
133	.determine_rate = meson_vclk_div_determine_rate,
134	.set_rate = meson_vclk_div_set_rate,
135	.enable = meson_vclk_div_enable,
136	.disable = meson_vclk_div_disable,
137	.is_enabled = meson_vclk_div_is_enabled,
138};
139EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, "CLK_MESON");
140
141MODULE_DESCRIPTION("Amlogic vclk clock driver");
142MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
143MODULE_LICENSE("GPL");
144MODULE_IMPORT_NS("CLK_MESON");
~/ Read-only file preview.