diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_dotclock.c')
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_dotclock.c | 206 |
1 files changed, 0 insertions, 206 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c deleted file mode 100644 index 417ade3d2565..000000000000 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2016 Free Electrons - * Copyright (C) 2016 NextThing Co - * - * Maxime Ripard <maxime.ripard@free-electrons.com> - */ - -#include <linux/clk-provider.h> -#include <linux/regmap.h> - -#include "sun4i_tcon.h" -#include "sun4i_dotclock.h" - -struct sun4i_dclk { - struct clk_hw hw; - struct regmap *regmap; - struct sun4i_tcon *tcon; -}; - -static inline struct sun4i_dclk *hw_to_dclk(struct clk_hw *hw) -{ - return container_of(hw, struct sun4i_dclk, hw); -} - -static void sun4i_dclk_disable(struct clk_hw *hw) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - - regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, - BIT(SUN4I_TCON0_DCLK_GATE_BIT), 0); -} - -static int sun4i_dclk_enable(struct clk_hw *hw) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - - return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, - BIT(SUN4I_TCON0_DCLK_GATE_BIT), - BIT(SUN4I_TCON0_DCLK_GATE_BIT)); -} - -static int sun4i_dclk_is_enabled(struct clk_hw *hw) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - u32 val; - - regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); - - return val & BIT(SUN4I_TCON0_DCLK_GATE_BIT); -} - -static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - u32 val; - - regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); - - val >>= SUN4I_TCON0_DCLK_DIV_SHIFT; - val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1; - - if (!val) - val = 1; - - return parent_rate / val; -} - -static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - struct sun4i_tcon *tcon = dclk->tcon; - unsigned long best_parent = 0; - u8 best_div = 1; - int i; - - for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) { - u64 ideal = (u64)rate * i; - unsigned long rounded; - - /* - * ideal has overflowed the max value that can be stored in an - * unsigned long, and every clk operation we might do on a - * truncated u64 value will give us incorrect results. - * Let's just stop there since bigger dividers will result in - * the same overflow issue. - */ - if (ideal > ULONG_MAX) - goto out; - - rounded = clk_hw_round_rate(clk_hw_get_parent(hw), - ideal); - - if (rounded == ideal) { - best_parent = rounded; - best_div = i; - goto out; - } - - if (abs(rate - rounded / i) < - abs(rate - best_parent / best_div)) { - best_parent = rounded; - best_div = i; - } - } - -out: - *parent_rate = best_parent; - - return best_parent / best_div; -} - -static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - u8 div = parent_rate / rate; - - return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, - GENMASK(6, 0), div); -} - -static int sun4i_dclk_get_phase(struct clk_hw *hw) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - u32 val; - - regmap_read(dclk->regmap, SUN4I_TCON0_IO_POL_REG, &val); - - val >>= 28; - val &= 3; - - return val * 120; -} - -static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) -{ - struct sun4i_dclk *dclk = hw_to_dclk(hw); - u32 val = degrees / 120; - - val <<= 28; - - regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, - GENMASK(29, 28), - val); - - return 0; -} - -static const struct clk_ops sun4i_dclk_ops = { - .disable = sun4i_dclk_disable, - .enable = sun4i_dclk_enable, - .is_enabled = sun4i_dclk_is_enabled, - - .recalc_rate = sun4i_dclk_recalc_rate, - .round_rate = sun4i_dclk_round_rate, - .set_rate = sun4i_dclk_set_rate, - - .get_phase = sun4i_dclk_get_phase, - .set_phase = sun4i_dclk_set_phase, -}; - -int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon) -{ - const char *clk_name, *parent_name; - struct clk_init_data init; - struct sun4i_dclk *dclk; - int ret; - - parent_name = __clk_get_name(tcon->sclk0); - ret = of_property_read_string_index(dev->of_node, - "clock-output-names", 0, - &clk_name); - if (ret) - return ret; - - dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL); - if (!dclk) - return -ENOMEM; - dclk->tcon = tcon; - - init.name = clk_name; - init.ops = &sun4i_dclk_ops; - init.parent_names = &parent_name; - init.num_parents = 1; - init.flags = CLK_SET_RATE_PARENT; - - dclk->regmap = tcon->regs; - dclk->hw.init = &init; - - tcon->dclk = clk_register(dev, &dclk->hw); - if (IS_ERR(tcon->dclk)) - return PTR_ERR(tcon->dclk); - - return 0; -} -EXPORT_SYMBOL(sun4i_dclk_create); - -int sun4i_dclk_free(struct sun4i_tcon *tcon) -{ - clk_unregister(tcon->dclk); - return 0; -} -EXPORT_SYMBOL(sun4i_dclk_free); |
