162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// OWL composite clock driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2014 Actions Semi Inc.
662306a36Sopenharmony_ci// Author: David Liu <liuwei@actions-semi.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Copyright (c) 2018 Linaro Ltd.
962306a36Sopenharmony_ci// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk-provider.h>
1262306a36Sopenharmony_ci#include <linux/regmap.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "owl-composite.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic u8 owl_comp_get_parent(struct clk_hw *hw)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	return owl_mux_helper_get_parent(&comp->common, &comp->mux_hw);
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int owl_comp_set_parent(struct clk_hw *hw, u8 index)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	return owl_mux_helper_set_parent(&comp->common, &comp->mux_hw, index);
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void owl_comp_disable(struct clk_hw *hw)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
3362306a36Sopenharmony_ci	struct owl_clk_common *common = &comp->common;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	owl_gate_set(common, &comp->gate_hw, false);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int owl_comp_enable(struct clk_hw *hw)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
4162306a36Sopenharmony_ci	struct owl_clk_common *common = &comp->common;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	owl_gate_set(common, &comp->gate_hw, true);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	return 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int owl_comp_is_enabled(struct clk_hw *hw)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
5162306a36Sopenharmony_ci	struct owl_clk_common *common = &comp->common;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return owl_gate_clk_is_enabled(common, &comp->gate_hw);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int owl_comp_div_determine_rate(struct clk_hw *hw,
5762306a36Sopenharmony_ci				       struct clk_rate_request *req)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
6062306a36Sopenharmony_ci	long rate;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	rate = owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw,
6362306a36Sopenharmony_ci					     req->rate, &req->best_parent_rate);
6462306a36Sopenharmony_ci	if (rate < 0)
6562306a36Sopenharmony_ci		return rate;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	req->rate = rate;
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw,
7262306a36Sopenharmony_ci					  unsigned long parent_rate)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return owl_divider_helper_recalc_rate(&comp->common, &comp->rate.div_hw,
7762306a36Sopenharmony_ci					parent_rate);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate,
8162306a36Sopenharmony_ci				unsigned long parent_rate)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return owl_divider_helper_set_rate(&comp->common, &comp->rate.div_hw,
8662306a36Sopenharmony_ci					rate, parent_rate);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int owl_comp_fact_determine_rate(struct clk_hw *hw,
9062306a36Sopenharmony_ci					struct clk_rate_request *req)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
9362306a36Sopenharmony_ci	long rate;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	rate = owl_factor_helper_round_rate(&comp->common,
9662306a36Sopenharmony_ci					    &comp->rate.factor_hw,
9762306a36Sopenharmony_ci					    req->rate, &req->best_parent_rate);
9862306a36Sopenharmony_ci	if (rate < 0)
9962306a36Sopenharmony_ci		return rate;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	req->rate = rate;
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw,
10662306a36Sopenharmony_ci			unsigned long parent_rate)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return owl_factor_helper_recalc_rate(&comp->common,
11162306a36Sopenharmony_ci					&comp->rate.factor_hw,
11262306a36Sopenharmony_ci					parent_rate);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate,
11662306a36Sopenharmony_ci			unsigned long parent_rate)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return owl_factor_helper_set_rate(&comp->common,
12162306a36Sopenharmony_ci					&comp->rate.factor_hw,
12262306a36Sopenharmony_ci					rate, parent_rate);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate,
12662306a36Sopenharmony_ci			unsigned long *parent_rate)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
12962306a36Sopenharmony_ci	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw,
13562306a36Sopenharmony_ci			unsigned long parent_rate)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct owl_composite *comp = hw_to_owl_comp(hw);
13862306a36Sopenharmony_ci	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate,
14562306a36Sopenharmony_ci			unsigned long parent_rate)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * We must report success but we can do so unconditionally because
14962306a36Sopenharmony_ci	 * owl_comp_fix_fact_round_rate returns values that ensure this call is
15062306a36Sopenharmony_ci	 * a nop.
15162306a36Sopenharmony_ci	 */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciconst struct clk_ops owl_comp_div_ops = {
15762306a36Sopenharmony_ci	/* mux_ops */
15862306a36Sopenharmony_ci	.get_parent	= owl_comp_get_parent,
15962306a36Sopenharmony_ci	.set_parent	= owl_comp_set_parent,
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* gate_ops */
16262306a36Sopenharmony_ci	.disable	= owl_comp_disable,
16362306a36Sopenharmony_ci	.enable		= owl_comp_enable,
16462306a36Sopenharmony_ci	.is_enabled	= owl_comp_is_enabled,
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* div_ops */
16762306a36Sopenharmony_ci	.determine_rate	= owl_comp_div_determine_rate,
16862306a36Sopenharmony_ci	.recalc_rate	= owl_comp_div_recalc_rate,
16962306a36Sopenharmony_ci	.set_rate	= owl_comp_div_set_rate,
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ciconst struct clk_ops owl_comp_fact_ops = {
17462306a36Sopenharmony_ci	/* mux_ops */
17562306a36Sopenharmony_ci	.get_parent	= owl_comp_get_parent,
17662306a36Sopenharmony_ci	.set_parent	= owl_comp_set_parent,
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* gate_ops */
17962306a36Sopenharmony_ci	.disable	= owl_comp_disable,
18062306a36Sopenharmony_ci	.enable		= owl_comp_enable,
18162306a36Sopenharmony_ci	.is_enabled	= owl_comp_is_enabled,
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* fact_ops */
18462306a36Sopenharmony_ci	.determine_rate	= owl_comp_fact_determine_rate,
18562306a36Sopenharmony_ci	.recalc_rate	= owl_comp_fact_recalc_rate,
18662306a36Sopenharmony_ci	.set_rate	= owl_comp_fact_set_rate,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciconst struct clk_ops owl_comp_fix_fact_ops = {
19062306a36Sopenharmony_ci	/* gate_ops */
19162306a36Sopenharmony_ci	.disable	= owl_comp_disable,
19262306a36Sopenharmony_ci	.enable		= owl_comp_enable,
19362306a36Sopenharmony_ci	.is_enabled	= owl_comp_is_enabled,
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* fix_fact_ops */
19662306a36Sopenharmony_ci	.round_rate	= owl_comp_fix_fact_round_rate,
19762306a36Sopenharmony_ci	.recalc_rate	= owl_comp_fix_fact_recalc_rate,
19862306a36Sopenharmony_ci	.set_rate	= owl_comp_fix_fact_set_rate,
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ciconst struct clk_ops owl_comp_pass_ops = {
20362306a36Sopenharmony_ci	/* mux_ops */
20462306a36Sopenharmony_ci	.determine_rate	= clk_hw_determine_rate_no_reparent,
20562306a36Sopenharmony_ci	.get_parent	= owl_comp_get_parent,
20662306a36Sopenharmony_ci	.set_parent	= owl_comp_set_parent,
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* gate_ops */
20962306a36Sopenharmony_ci	.disable	= owl_comp_disable,
21062306a36Sopenharmony_ci	.enable		= owl_comp_enable,
21162306a36Sopenharmony_ci	.is_enabled	= owl_comp_is_enabled,
21262306a36Sopenharmony_ci};
213