diff options
Diffstat (limited to 'drivers/clk/meson/clk-audio-divider.c')
-rw-r--r-- | drivers/clk/meson/clk-audio-divider.c | 63 |
1 files changed, 20 insertions, 43 deletions
diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c index 6c07db06642d..f7ab5b1db342 100644 --- a/drivers/clk/meson/clk-audio-divider.c +++ b/drivers/clk/meson/clk-audio-divider.c | |||
@@ -28,8 +28,11 @@ | |||
28 | #include <linux/clk-provider.h> | 28 | #include <linux/clk-provider.h> |
29 | #include "clkc.h" | 29 | #include "clkc.h" |
30 | 30 | ||
31 | #define to_meson_clk_audio_divider(_hw) container_of(_hw, \ | 31 | static inline struct meson_clk_audio_div_data * |
32 | struct meson_clk_audio_divider, hw) | 32 | meson_clk_audio_div_data(struct clk_regmap *clk) |
33 | { | ||
34 | return (struct meson_clk_audio_div_data *)clk->data; | ||
35 | } | ||
33 | 36 | ||
34 | static int _div_round(unsigned long parent_rate, unsigned long rate, | 37 | static int _div_round(unsigned long parent_rate, unsigned long rate, |
35 | unsigned long flags) | 38 | unsigned long flags) |
@@ -45,15 +48,9 @@ static int _get_val(unsigned long parent_rate, unsigned long rate) | |||
45 | return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; | 48 | return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; |
46 | } | 49 | } |
47 | 50 | ||
48 | static int _valid_divider(struct clk_hw *hw, int divider) | 51 | static int _valid_divider(unsigned int width, int divider) |
49 | { | 52 | { |
50 | struct meson_clk_audio_divider *adiv = | 53 | int max_divider = 1 << width; |
51 | to_meson_clk_audio_divider(hw); | ||
52 | int max_divider; | ||
53 | u8 width; | ||
54 | |||
55 | width = adiv->div.width; | ||
56 | max_divider = 1 << width; | ||
57 | 54 | ||
58 | return clamp(divider, 1, max_divider); | 55 | return clamp(divider, 1, max_divider); |
59 | } | 56 | } |
@@ -61,14 +58,11 @@ static int _valid_divider(struct clk_hw *hw, int divider) | |||
61 | static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, | 58 | static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, |
62 | unsigned long parent_rate) | 59 | unsigned long parent_rate) |
63 | { | 60 | { |
64 | struct meson_clk_audio_divider *adiv = | 61 | struct clk_regmap *clk = to_clk_regmap(hw); |
65 | to_meson_clk_audio_divider(hw); | 62 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); |
66 | struct parm *p; | 63 | unsigned long divider; |
67 | unsigned long reg, divider; | ||
68 | 64 | ||
69 | p = &adiv->div; | 65 | divider = meson_parm_read(clk->map, &adiv->div); |
70 | reg = readl(adiv->base + p->reg_off); | ||
71 | divider = PARM_GET(p->width, p->shift, reg) + 1; | ||
72 | 66 | ||
73 | return DIV_ROUND_UP_ULL((u64)parent_rate, divider); | 67 | return DIV_ROUND_UP_ULL((u64)parent_rate, divider); |
74 | } | 68 | } |
@@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw, | |||
77 | unsigned long rate, | 71 | unsigned long rate, |
78 | unsigned long *parent_rate) | 72 | unsigned long *parent_rate) |
79 | { | 73 | { |
80 | struct meson_clk_audio_divider *adiv = | 74 | struct clk_regmap *clk = to_clk_regmap(hw); |
81 | to_meson_clk_audio_divider(hw); | 75 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); |
82 | unsigned long max_prate; | 76 | unsigned long max_prate; |
83 | int divider; | 77 | int divider; |
84 | 78 | ||
85 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { | 79 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { |
86 | divider = _div_round(*parent_rate, rate, adiv->flags); | 80 | divider = _div_round(*parent_rate, rate, adiv->flags); |
87 | divider = _valid_divider(hw, divider); | 81 | divider = _valid_divider(adiv->div.width, divider); |
88 | return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); | 82 | return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); |
89 | } | 83 | } |
90 | 84 | ||
@@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw, | |||
93 | 87 | ||
94 | /* Get the corresponding rounded down divider */ | 88 | /* Get the corresponding rounded down divider */ |
95 | divider = max_prate / rate; | 89 | divider = max_prate / rate; |
96 | divider = _valid_divider(hw, divider); | 90 | divider = _valid_divider(adiv->div.width, divider); |
97 | 91 | ||
98 | /* Get actual rate of the parent */ | 92 | /* Get actual rate of the parent */ |
99 | *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), | 93 | *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), |
@@ -106,28 +100,11 @@ static int audio_divider_set_rate(struct clk_hw *hw, | |||
106 | unsigned long rate, | 100 | unsigned long rate, |
107 | unsigned long parent_rate) | 101 | unsigned long parent_rate) |
108 | { | 102 | { |
109 | struct meson_clk_audio_divider *adiv = | 103 | struct clk_regmap *clk = to_clk_regmap(hw); |
110 | to_meson_clk_audio_divider(hw); | 104 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); |
111 | struct parm *p; | 105 | int val = _get_val(parent_rate, rate); |
112 | unsigned long reg, flags = 0; | 106 | |
113 | int val; | 107 | meson_parm_write(clk->map, &adiv->div, val); |
114 | |||
115 | val = _get_val(parent_rate, rate); | ||
116 | |||
117 | if (adiv->lock) | ||
118 | spin_lock_irqsave(adiv->lock, flags); | ||
119 | else | ||
120 | __acquire(adiv->lock); | ||
121 | |||
122 | p = &adiv->div; | ||
123 | reg = readl(adiv->base + p->reg_off); | ||
124 | reg = PARM_SET(p->width, p->shift, reg, val); | ||
125 | writel(reg, adiv->base + p->reg_off); | ||
126 | |||
127 | if (adiv->lock) | ||
128 | spin_unlock_irqrestore(adiv->lock, flags); | ||
129 | else | ||
130 | __release(adiv->lock); | ||
131 | 108 | ||
132 | return 0; | 109 | return 0; |
133 | } | 110 | } |