Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

Need help to get security updates for your Linux BSP?
Loading...
Note: File does not exist in v3.15.
  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	.enable = meson_vclk_gate_enable,
 49	.disable = meson_vclk_gate_disable,
 50	.is_enabled = meson_vclk_gate_is_enabled,
 51};
 52EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, "CLK_MESON");
 53
 54/* The VCLK Divider has supplementary reset & enable bits */
 55
 56static inline struct meson_vclk_div_data *
 57clk_get_meson_vclk_div_data(struct clk_regmap *clk)
 58{
 59	return (struct meson_vclk_div_data *)clk->data;
 60}
 61
 62static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
 63						unsigned long prate)
 64{
 65	struct clk_regmap *clk = to_clk_regmap(hw);
 66	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 67
 68	return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div),
 69				   vclk->table, vclk->flags, vclk->div.width);
 70}
 71
 72static int meson_vclk_div_determine_rate(struct clk_hw *hw,
 73					 struct clk_rate_request *req)
 74{
 75	struct clk_regmap *clk = to_clk_regmap(hw);
 76	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 77
 78	return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
 79				      vclk->flags);
 80}
 81
 82static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
 83				   unsigned long parent_rate)
 84{
 85	struct clk_regmap *clk = to_clk_regmap(hw);
 86	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
 87	int ret;
 88
 89	ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
 90			      vclk->flags);
 91	if (ret < 0)
 92		return ret;
 93
 94	meson_parm_write(clk->map, &vclk->div, ret);
 95
 96	return 0;
 97};
 98
 99static int meson_vclk_div_enable(struct clk_hw *hw)
100{
101	struct clk_regmap *clk = to_clk_regmap(hw);
102	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
103
104	/* Unreset the divider when ungating */
105	meson_parm_write(clk->map, &vclk->reset, 0);
106	meson_parm_write(clk->map, &vclk->enable, 1);
107
108	return 0;
109}
110
111static void meson_vclk_div_disable(struct clk_hw *hw)
112{
113	struct clk_regmap *clk = to_clk_regmap(hw);
114	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
115
116	/* Reset the divider when gating */
117	meson_parm_write(clk->map, &vclk->enable, 0);
118	meson_parm_write(clk->map, &vclk->reset, 1);
119}
120
121static int meson_vclk_div_is_enabled(struct clk_hw *hw)
122{
123	struct clk_regmap *clk = to_clk_regmap(hw);
124	struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
125
126	return meson_parm_read(clk->map, &vclk->enable);
127}
128
129const struct clk_ops meson_vclk_div_ops = {
130	.recalc_rate = meson_vclk_div_recalc_rate,
131	.determine_rate = meson_vclk_div_determine_rate,
132	.set_rate = meson_vclk_div_set_rate,
133	.enable = meson_vclk_div_enable,
134	.disable = meson_vclk_div_disable,
135	.is_enabled = meson_vclk_div_is_enabled,
136};
137EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, "CLK_MESON");
138
139MODULE_DESCRIPTION("Amlogic vclk clock driver");
140MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
141MODULE_LICENSE("GPL");
142MODULE_IMPORT_NS("CLK_MESON");