#include <linux/clk-provider.h>
#include "clkc.h"
-#define to_meson_clk_audio_divider(_hw) container_of(_hw, \
- struct meson_clk_audio_divider, hw)
+static inline struct meson_clk_audio_div_data *
+meson_clk_audio_div_data(struct clk_regmap *clk)
+{
+ return (struct meson_clk_audio_div_data *)clk->data;
+}
static int _div_round(unsigned long parent_rate, unsigned long rate,
unsigned long flags)
return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
}
-static int _valid_divider(struct clk_hw *hw, int divider)
+static int _valid_divider(unsigned int width, int divider)
{
- struct meson_clk_audio_divider *adiv =
- to_meson_clk_audio_divider(hw);
- int max_divider;
- u8 width;
-
- width = adiv->div.width;
- max_divider = 1 << width;
+ int max_divider = 1 << width;
return clamp(divider, 1, max_divider);
}
static unsigned long audio_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- struct meson_clk_audio_divider *adiv =
- to_meson_clk_audio_divider(hw);
- struct parm *p;
- unsigned long reg, divider;
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
+ unsigned long divider;
- p = &adiv->div;
- reg = readl(adiv->base + p->reg_off);
- divider = PARM_GET(p->width, p->shift, reg) + 1;
+ divider = meson_parm_read(clk->map, &adiv->div);
return DIV_ROUND_UP_ULL((u64)parent_rate, divider);
}
unsigned long rate,
unsigned long *parent_rate)
{
- struct meson_clk_audio_divider *adiv =
- to_meson_clk_audio_divider(hw);
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
unsigned long max_prate;
int divider;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
divider = _div_round(*parent_rate, rate, adiv->flags);
- divider = _valid_divider(hw, divider);
+ divider = _valid_divider(adiv->div.width, divider);
return DIV_ROUND_UP_ULL((u64)*parent_rate, divider);
}
/* Get the corresponding rounded down divider */
divider = max_prate / rate;
- divider = _valid_divider(hw, divider);
+ divider = _valid_divider(adiv->div.width, divider);
/* Get actual rate of the parent */
*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
unsigned long rate,
unsigned long parent_rate)
{
- struct meson_clk_audio_divider *adiv =
- to_meson_clk_audio_divider(hw);
- struct parm *p;
- unsigned long reg, flags = 0;
- int val;
-
- val = _get_val(parent_rate, rate);
-
- if (adiv->lock)
- spin_lock_irqsave(adiv->lock, flags);
- else
- __acquire(adiv->lock);
-
- p = &adiv->div;
- reg = readl(adiv->base + p->reg_off);
- reg = PARM_SET(p->width, p->shift, reg, val);
- writel(reg, adiv->base + p->reg_off);
-
- if (adiv->lock)
- spin_unlock_irqrestore(adiv->lock, flags);
- else
- __release(adiv->lock);
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk);
+ int val = _get_val(parent_rate, rate);
+
+ meson_parm_write(clk->map, &adiv->div, val);
return 0;
}
},
};
-static struct meson_clk_audio_divider gxbb_cts_amclk_div = {
- .div = {
- .reg_off = HHI_AUD_CLK_CNTL,
- .shift = 0,
- .width = 8,
+static struct clk_regmap gxbb_cts_amclk_div = {
+ .data = &(struct meson_clk_audio_div_data){
+ .div = {
+ .reg_off = HHI_AUD_CLK_CNTL,
+ .shift = 0,
+ .width = 8,
+ },
+ .flags = CLK_DIVIDER_ROUND_CLOSEST,
},
- .flags = CLK_DIVIDER_ROUND_CLOSEST,
- .lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){
.name = "cts_amclk_div",
.ops = &meson_clk_audio_divider_ops,
&gxl_gp0_pll,
};
-static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
- &gxbb_cts_amclk_div,
-};
-
static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_clk81,
&gxbb_ddr,
&gxbb_mpll0,
&gxbb_mpll1,
&gxbb_mpll2,
+ &gxbb_cts_amclk_div,
};
struct clkc_data {
struct meson_clk_pll *const *clk_plls;
unsigned int clk_plls_count;
- struct meson_clk_audio_divider *const *clk_audio_dividers;
- unsigned int clk_audio_dividers_count;
struct clk_hw_onecell_data *hw_onecell_data;
};
static const struct clkc_data gxbb_clkc_data = {
.clk_plls = gxbb_clk_plls,
.clk_plls_count = ARRAY_SIZE(gxbb_clk_plls),
- .clk_audio_dividers = gxbb_audio_dividers,
- .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers),
.hw_onecell_data = &gxbb_hw_onecell_data,
};
static const struct clkc_data gxl_clkc_data = {
.clk_plls = gxl_clk_plls,
.clk_plls_count = ARRAY_SIZE(gxl_clk_plls),
- .clk_audio_dividers = gxbb_audio_dividers,
- .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers),
.hw_onecell_data = &gxl_hw_onecell_data,
};
for (i = 0; i < clkc_data->clk_plls_count; i++)
clkc_data->clk_plls[i]->base = clk_base;
- /* Populate base address for the audio dividers */
- for (i = 0; i < clkc_data->clk_audio_dividers_count; i++)
- clkc_data->clk_audio_dividers[i]->base = clk_base;
-
/* Populate regmap for the common regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++)
gx_clk_regmaps[i]->map = map;