mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
2.4 KiB
94 lines
2.4 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
// |
|
// OWL divider clock driver |
|
// |
|
// Copyright (c) 2014 Actions Semi Inc. |
|
// Author: David Liu <[email protected]> |
|
// |
|
// Copyright (c) 2018 Linaro Ltd. |
|
// Author: Manivannan Sadhasivam <[email protected]> |
|
|
|
#include <linux/clk-provider.h> |
|
#include <linux/regmap.h> |
|
|
|
#include "owl-divider.h" |
|
|
|
long owl_divider_helper_round_rate(struct owl_clk_common *common, |
|
const struct owl_divider_hw *div_hw, |
|
unsigned long rate, |
|
unsigned long *parent_rate) |
|
{ |
|
return divider_round_rate(&common->hw, rate, parent_rate, |
|
div_hw->table, div_hw->width, |
|
div_hw->div_flags); |
|
} |
|
|
|
static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
|
unsigned long *parent_rate) |
|
{ |
|
struct owl_divider *div = hw_to_owl_divider(hw); |
|
|
|
return owl_divider_helper_round_rate(&div->common, &div->div_hw, |
|
rate, parent_rate); |
|
} |
|
|
|
unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, |
|
const struct owl_divider_hw *div_hw, |
|
unsigned long parent_rate) |
|
{ |
|
unsigned long val; |
|
unsigned int reg; |
|
|
|
regmap_read(common->regmap, div_hw->reg, ®); |
|
val = reg >> div_hw->shift; |
|
val &= (1 << div_hw->width) - 1; |
|
|
|
return divider_recalc_rate(&common->hw, parent_rate, |
|
val, div_hw->table, |
|
div_hw->div_flags, |
|
div_hw->width); |
|
} |
|
|
|
static unsigned long owl_divider_recalc_rate(struct clk_hw *hw, |
|
unsigned long parent_rate) |
|
{ |
|
struct owl_divider *div = hw_to_owl_divider(hw); |
|
|
|
return owl_divider_helper_recalc_rate(&div->common, |
|
&div->div_hw, parent_rate); |
|
} |
|
|
|
int owl_divider_helper_set_rate(const struct owl_clk_common *common, |
|
const struct owl_divider_hw *div_hw, |
|
unsigned long rate, |
|
unsigned long parent_rate) |
|
{ |
|
unsigned long val; |
|
unsigned int reg; |
|
|
|
val = divider_get_val(rate, parent_rate, div_hw->table, |
|
div_hw->width, 0); |
|
|
|
regmap_read(common->regmap, div_hw->reg, ®); |
|
reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); |
|
|
|
regmap_write(common->regmap, div_hw->reg, |
|
reg | (val << div_hw->shift)); |
|
|
|
return 0; |
|
} |
|
|
|
static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
|
unsigned long parent_rate) |
|
{ |
|
struct owl_divider *div = hw_to_owl_divider(hw); |
|
|
|
return owl_divider_helper_set_rate(&div->common, &div->div_hw, |
|
rate, parent_rate); |
|
} |
|
|
|
const struct clk_ops owl_divider_ops = { |
|
.recalc_rate = owl_divider_recalc_rate, |
|
.round_rate = owl_divider_round_rate, |
|
.set_rate = owl_divider_set_rate, |
|
};
|
|
|