Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/clk/actions/owl-divider.c
50904 views
1
// SPDX-License-Identifier: GPL-2.0+
2
//
3
// OWL divider clock driver
4
//
5
// Copyright (c) 2014 Actions Semi Inc.
6
// Author: David Liu <[email protected]>
7
//
8
// Copyright (c) 2018 Linaro Ltd.
9
// Author: Manivannan Sadhasivam <[email protected]>
10
11
#include <linux/clk-provider.h>
12
#include <linux/regmap.h>
13
14
#include "owl-divider.h"
15
16
long owl_divider_helper_round_rate(struct owl_clk_common *common,
17
const struct owl_divider_hw *div_hw,
18
unsigned long rate,
19
unsigned long *parent_rate)
20
{
21
return divider_round_rate(&common->hw, rate, parent_rate,
22
div_hw->table, div_hw->width,
23
div_hw->div_flags);
24
}
25
26
static int owl_divider_determine_rate(struct clk_hw *hw,
27
struct clk_rate_request *req)
28
{
29
struct owl_divider *div = hw_to_owl_divider(hw);
30
31
req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw,
32
req->rate,
33
&req->best_parent_rate);
34
35
return 0;
36
}
37
38
unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common,
39
const struct owl_divider_hw *div_hw,
40
unsigned long parent_rate)
41
{
42
unsigned long val;
43
unsigned int reg;
44
45
regmap_read(common->regmap, div_hw->reg, &reg);
46
val = reg >> div_hw->shift;
47
val &= (1 << div_hw->width) - 1;
48
49
return divider_recalc_rate(&common->hw, parent_rate,
50
val, div_hw->table,
51
div_hw->div_flags,
52
div_hw->width);
53
}
54
55
static unsigned long owl_divider_recalc_rate(struct clk_hw *hw,
56
unsigned long parent_rate)
57
{
58
struct owl_divider *div = hw_to_owl_divider(hw);
59
60
return owl_divider_helper_recalc_rate(&div->common,
61
&div->div_hw, parent_rate);
62
}
63
64
int owl_divider_helper_set_rate(const struct owl_clk_common *common,
65
const struct owl_divider_hw *div_hw,
66
unsigned long rate,
67
unsigned long parent_rate)
68
{
69
unsigned long val;
70
unsigned int reg;
71
72
val = divider_get_val(rate, parent_rate, div_hw->table,
73
div_hw->width, 0);
74
75
regmap_read(common->regmap, div_hw->reg, &reg);
76
reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift);
77
78
regmap_write(common->regmap, div_hw->reg,
79
reg | (val << div_hw->shift));
80
81
return 0;
82
}
83
84
static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate,
85
unsigned long parent_rate)
86
{
87
struct owl_divider *div = hw_to_owl_divider(hw);
88
89
return owl_divider_helper_set_rate(&div->common, &div->div_hw,
90
rate, parent_rate);
91
}
92
93
const struct clk_ops owl_divider_ops = {
94
.recalc_rate = owl_divider_recalc_rate,
95
.determine_rate = owl_divider_determine_rate,
96
.set_rate = owl_divider_set_rate,
97
};
98
99