mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
rk_clk: modify clk-ops.c to reuse and fit the common clk framework.
After the .determine_rate operation was introduced, many ops and clocks can be implemented more easily by the common clock framework, and many unnessary old codes can be removed as a result.
This commit is contained in:
@@ -276,6 +276,7 @@
|
||||
clocks = <&clk_i2s_div>, <&clk_i2s_frac>, <&xin12m>;
|
||||
clock-output-names = "clk_i2s";
|
||||
rockchip,clkops-idx = <CLKOPS_RATE_I2S>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
@@ -308,6 +309,7 @@
|
||||
clocks = <&clk_spdif_div>, <&clk_spdif_frac>, <&xin12m>;
|
||||
clock-output-names = "clk_spdif";
|
||||
rockchip,clkops-idx = <CLKOPS_RATE_I2S>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
@@ -496,6 +498,7 @@
|
||||
<&xin24m>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_uart0";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -528,6 +531,7 @@
|
||||
<&xin24m>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_uart1";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -560,6 +564,7 @@
|
||||
<&xin24m>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_uart2";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -592,6 +597,7 @@
|
||||
<&xin24m>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_uart3";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -612,7 +618,7 @@
|
||||
/* numerator denominator */
|
||||
rockchip,bits = <0 32>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART_FRAC>;
|
||||
<CLKOPS_RATE_FRAC>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
@@ -628,7 +634,7 @@
|
||||
/* numerator denominator */
|
||||
rockchip,bits = <0 32>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART_FRAC>;
|
||||
<CLKOPS_RATE_FRAC>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
@@ -644,7 +650,7 @@
|
||||
/* numerator denominator */
|
||||
rockchip,bits = <0 32>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART_FRAC>;
|
||||
<CLKOPS_RATE_FRAC>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
@@ -660,7 +666,7 @@
|
||||
/* numerator denominator */
|
||||
rockchip,bits = <0 32>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_UART_FRAC>;
|
||||
<CLKOPS_RATE_FRAC>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
@@ -687,6 +693,7 @@
|
||||
clocks = <&clk_mac_pll_mux>, <&rmii_clkin>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_MAC_REF>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_mac";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -697,6 +704,8 @@
|
||||
compatible = "rockchip,rk3188-div-con";
|
||||
rockchip,bits = <8 5>;
|
||||
clocks = <&clk_mac_pll_mux>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_MUX_DIV>;
|
||||
rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
|
||||
|
||||
};
|
||||
@@ -727,6 +736,7 @@
|
||||
<&clk_hsadc_ext>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_HSADC>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_hsadc";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
@@ -762,7 +772,7 @@
|
||||
/* numerator denominator */
|
||||
rockchip,bits = <0 32>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_HSADC_FRAC>;
|
||||
<CLKOPS_RATE_FRAC>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
||||
@@ -907,6 +917,8 @@
|
||||
rockchip,bits = <1 5>;
|
||||
clocks = <&cif_out_pll_mux>;
|
||||
rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_MUX_DIV>;
|
||||
};
|
||||
|
||||
/* reg[6]: reserved */
|
||||
@@ -917,6 +929,7 @@
|
||||
clocks = <&cif_out_pll_mux>, <&xin24m>;
|
||||
rockchip,clkops-idx =
|
||||
<CLKOPS_RATE_CIFOUT>;
|
||||
rockchip,flags = <CLK_SET_RATE_PARENT>;
|
||||
clock-output-names = "clk_cif0";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
@@ -5,18 +5,22 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include "clk-ops.h"
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "clk-ops.h"
|
||||
|
||||
|
||||
|
||||
/* mux_ops */
|
||||
struct clk_ops_table rk_clk_mux_ops_table[] = {
|
||||
{.index = CLKOPS_TABLE_END},
|
||||
};
|
||||
|
||||
|
||||
/* rate_ops */
|
||||
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
|
||||
#define div_mask(d) ((1 << ((d)->width)) - 1)
|
||||
|
||||
#define MHZ (1000 * 1000)
|
||||
static u32 clk_gcd(u32 numerator, u32 denominator)
|
||||
{
|
||||
u32 a, b;
|
||||
@@ -48,7 +52,7 @@ static int clk_fracdiv_get_config(unsigned long rate_out, unsigned long rate,
|
||||
__func__, rate_out, rate, gcd_val);
|
||||
|
||||
if (!gcd_val) {
|
||||
clk_err("gcd=0, i2s frac div is not be supported\n");
|
||||
clk_err("gcd=0, frac div is not be supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -75,21 +79,17 @@ static int clk_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
u32 numerator, denominator;
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
|
||||
struct clk *clk_parent = hw->clk->parent;
|
||||
|
||||
if(clk_fracdiv_get_config(rate, parent_rate,
|
||||
&numerator, &denominator) == 0) {
|
||||
|
||||
clk_parent->ops->set_rate(clk_parent->hw,
|
||||
clk_parent->parent->rate,
|
||||
clk_parent->parent->rate);
|
||||
writel(numerator << 16 | denominator, div->reg);
|
||||
clk_err("%s set rate=%lu,is ok\n", hw->clk->name, rate);
|
||||
|
||||
clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate);
|
||||
} else {
|
||||
clk_err("clk_frac_div can't get rate=%lu,%s\n",
|
||||
rate, hw->clk->name);
|
||||
return -ENOENT;
|
||||
clk_err("clk_frac_div name=%s can't get rate=%lu\n",
|
||||
hw->clk->name, rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,9 +100,11 @@ static unsigned long clk_fracdiv_recalc(struct clk_hw *hw,
|
||||
u64 rate64;
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
u32 numerator, denominator, reg_val;
|
||||
|
||||
reg_val = readl(div->reg);
|
||||
if (reg_val == 0)
|
||||
return parent_rate;
|
||||
|
||||
numerator = reg_val >> 16;
|
||||
denominator = reg_val & 0xFFFF;
|
||||
rate64 = (u64)parent_rate * numerator;
|
||||
@@ -113,172 +115,102 @@ static unsigned long clk_fracdiv_recalc(struct clk_hw *hw,
|
||||
numerator, denominator);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long clk_fracdiv_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
/*************************************************************************/
|
||||
/* rate_ops */
|
||||
#define PARENTS_NUM_MAX 3
|
||||
/*
|
||||
* get the best rate from array of available rates, regarding rate which is smaller than
|
||||
* and most close to the set_rate as the best.
|
||||
*/
|
||||
static long get_best_rate(unsigned long array[],unsigned int num, int *n, long rate)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned long best_rate = 0;
|
||||
|
||||
for(i = 0; i < num; i++){
|
||||
if(array[i] == rate){
|
||||
*n = i;
|
||||
return array[i];
|
||||
}else if((array[i] < rate) && (array[i] > best_rate)){
|
||||
best_rate = array[i];
|
||||
*n = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(best_rate == 0){
|
||||
clk_err("NOT array rate is <= %lu\n", rate);
|
||||
}else{
|
||||
clk_debug("get the best available rate,but it != %lu you want to set!\n", rate);
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static struct clk *clk_get_best_parent(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned int *div_out)
|
||||
{
|
||||
struct clk *clk = hw->clk;
|
||||
u32 div[PARENTS_NUM_MAX] = {0};
|
||||
unsigned long new_rate[PARENTS_NUM_MAX] = {0};
|
||||
unsigned long best_rate;
|
||||
u32 i;
|
||||
struct clk *parent = clk->parent;
|
||||
long rate_out;
|
||||
|
||||
memset(div, 0, sizeof(div));
|
||||
memset(new_rate, 0, sizeof(new_rate));
|
||||
//FIXME: now just simply return rate
|
||||
/*
|
||||
*frac_div request a big input rate, and its parent is always a div,
|
||||
*so we set parent->parent->rate as best_parent_rate.
|
||||
*/
|
||||
rate_out = rate;
|
||||
*prate = parent->parent->rate;
|
||||
|
||||
if(clk->rate == rate)
|
||||
return clk->parent;
|
||||
|
||||
for(i = 0; i < clk->num_parents; i++) {
|
||||
new_rate[i] = clk_divider_ops.round_rate(hw, rate,
|
||||
&(clk->parents[i]->rate));
|
||||
div[i] = (clk->parents[i]->rate)/new_rate[i];
|
||||
if(new_rate[i] == rate) {
|
||||
*div_out = div[i];
|
||||
return clk->parents[i];
|
||||
}
|
||||
}
|
||||
|
||||
best_rate = get_best_rate(new_rate, PARENTS_NUM_MAX, &i, rate);
|
||||
if(best_rate == 0){
|
||||
clk_err("NOT rate is good!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*div_out = div[i];
|
||||
|
||||
return clk->parents[i];
|
||||
}
|
||||
|
||||
static long clk_div_round_rate_autosel_parents(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *prate)
|
||||
{
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *new_parent;
|
||||
int new_div;
|
||||
|
||||
if(clk->rate == rate)
|
||||
return rate;
|
||||
|
||||
new_parent = clk_get_best_parent(hw, rate, &new_div);
|
||||
if(!new_parent || (new_div <= 0)){
|
||||
clk_err("%s: clk %s could not get new_parent or new_div\n",
|
||||
__func__,clk->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return (new_parent->rate)/new_div;
|
||||
}
|
||||
|
||||
|
||||
static int clk_div_set_rate_autosel_parents(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
//struct clk_divider *divider = to_clk_divider(hw);
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *new_parent;
|
||||
unsigned int new_div,old_div;
|
||||
unsigned long new_rate;
|
||||
int ret = 0;
|
||||
u8 index;
|
||||
int i;
|
||||
|
||||
if(clk->rate == rate)
|
||||
goto out;
|
||||
|
||||
new_parent = clk_get_best_parent(hw, rate, &new_div);
|
||||
if(!new_parent || (new_div == 0)){
|
||||
clk_err("%s: clk %s could not get new_parent or get "
|
||||
"new_div = 0\n", __func__,clk->name);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_div = (clk->parent->rate)/(clk->rate);
|
||||
|
||||
clk_debug("%s:%d: %s: %lu\n", __func__, __LINE__,
|
||||
clk->parent->name, new_parent->rate);
|
||||
if(new_div > old_div){
|
||||
new_rate = (clk->parent->rate)/new_div;
|
||||
ret = clk_divider_ops.set_rate(hw, new_rate,
|
||||
(clk->parent->rate));
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(clk->parent != new_parent){
|
||||
for(i=0; i<clk->num_parents; i++){
|
||||
if(new_parent == clk->parents[i]){
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ret = clk->ops->set_parent(clk->hw, index);
|
||||
* if(ret)
|
||||
* goto out;
|
||||
*/
|
||||
clk_set_parent(clk, new_parent);
|
||||
clk->ops->recalc_rate(clk->hw, clk->parent->rate);
|
||||
}
|
||||
|
||||
if(new_div <= old_div){
|
||||
new_rate = (clk->parent->rate)/new_div;
|
||||
ret = clk_divider_ops.set_rate(hw, new_rate,
|
||||
(clk->parent->rate));
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return rate_out;
|
||||
}
|
||||
|
||||
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return clk_divider_ops.recalc_rate(hw, hw->clk->parent->rate);
|
||||
return clk_divider_ops.recalc_rate(hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_divider_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *prate)
|
||||
{
|
||||
return clk_divider_ops.round_rate(hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_divider_set_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
return clk_divider_ops.set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_mux_with_div_determine_rate(struct clk_hw *div_hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk **best_parent_p)
|
||||
{
|
||||
struct clk *clk = div_hw->clk, *parent = NULL, *best_parent = NULL;
|
||||
int i, num_parents;
|
||||
unsigned long parent_rate = 0, best_prate = 0, best = 0, now = 0;
|
||||
|
||||
|
||||
parent = __clk_get_parent(clk);
|
||||
if(!parent){
|
||||
best = __clk_get_rate(clk);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if NO_REPARENT flag set, pass through to current parent */
|
||||
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
|
||||
best_prate = __clk_get_rate(parent);
|
||||
best = clk_divider_ops.round_rate(div_hw, rate, &best_prate);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* find the parent that can provide the fastest rate <= rate */
|
||||
num_parents = clk->num_parents;
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent = clk_get_parent_by_index(clk, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
now = clk_divider_ops.round_rate(div_hw, rate, &parent_rate);
|
||||
|
||||
if (now <= rate && now > best) {
|
||||
best_parent = parent;
|
||||
best_prate = parent_rate;
|
||||
best = now;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if(best_prate)
|
||||
*best_parent_rate = best_prate;
|
||||
|
||||
if (best_parent)
|
||||
*best_parent_p = best_parent;
|
||||
|
||||
clk_debug("clk name = %s, determine rate = %lu, best = %lu\n"
|
||||
"\tbest_parent name = %s, best_prate = %lu\n",
|
||||
clk->name, rate, best,
|
||||
__clk_get_name(*best_parent_p), *best_parent_rate);
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
const struct clk_ops clkops_rate_auto_parent = {
|
||||
.recalc_rate = clk_divider_recalc_rate,
|
||||
.round_rate = clk_div_round_rate_autosel_parents,
|
||||
.set_rate = clk_div_set_rate_autosel_parents,
|
||||
.round_rate = clk_divider_round_rate,
|
||||
.set_rate = clk_divider_set_rate,
|
||||
.determine_rate = clk_mux_with_div_determine_rate,
|
||||
};
|
||||
|
||||
static long clk_div_round_rate_even(struct clk_hw *hw, unsigned long rate,
|
||||
@@ -300,7 +232,7 @@ static long clk_div_round_rate_even(struct clk_hw *hw, unsigned long rate,
|
||||
static int clk_div_set_rate_even(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return clk_divider_ops.set_rate(hw, rate, hw->clk->parent->rate);
|
||||
return clk_divider_ops.set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
const struct clk_ops clkops_rate_evendiv = {
|
||||
@@ -314,9 +246,9 @@ static long dclk_lcdc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
long ret = 0;
|
||||
if (rate == 27 * MHZ) {
|
||||
ret = clk_div_round_rate_autosel_parents(hw, rate, prate);
|
||||
ret = clk_divider_round_rate(hw, rate, prate);
|
||||
} else {
|
||||
ret = clk_div_round_rate_autosel_parents(hw, rate, prate);
|
||||
ret = clk_divider_round_rate(hw, rate, prate);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -324,81 +256,17 @@ static long dclk_lcdc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static int dclk_lcdc_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return clk_div_set_rate_autosel_parents(hw, rate, parent_rate);
|
||||
return clk_divider_set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
const struct clk_ops clkops_rate_dclk_lcdc = {
|
||||
.recalc_rate = clk_divider_recalc_rate,
|
||||
.round_rate = dclk_lcdc_round_rate,
|
||||
.set_rate = dclk_lcdc_set_rate,
|
||||
.determine_rate = clk_mux_with_div_determine_rate,
|
||||
};
|
||||
|
||||
#define CIF_OUT_SRC_DIV (0x0)
|
||||
#define CIF_OUT_SRC_24M (0x1)
|
||||
|
||||
static unsigned long cif_out_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return hw->clk->parent->rate;
|
||||
}
|
||||
|
||||
static long cif_out_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *parent;
|
||||
|
||||
if (rate == clk->parents[CIF_OUT_SRC_24M]->rate) {
|
||||
return rate;
|
||||
} else {
|
||||
parent = clk->parents[CIF_OUT_SRC_DIV];
|
||||
return parent->ops->round_rate(parent->hw, rate,
|
||||
&(parent->parent->rate));
|
||||
}
|
||||
}
|
||||
|
||||
static int cif_out_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *parent;
|
||||
int ret = 0;
|
||||
|
||||
if (rate == clk->parents[CIF_OUT_SRC_24M]->rate) {
|
||||
parent = clk->parents[CIF_OUT_SRC_24M];
|
||||
} else {
|
||||
parent = clk->parents[CIF_OUT_SRC_DIV];
|
||||
ret = parent->ops->set_rate(parent->hw, rate,
|
||||
parent->parent->rate);
|
||||
if (ret)
|
||||
goto out;
|
||||
else
|
||||
parent->rate = rate;
|
||||
}
|
||||
|
||||
if(clk->parent != parent){
|
||||
ret = clk_set_parent(clk, parent);
|
||||
#if 0
|
||||
for(i=0; i<clk->num_parents; i++){
|
||||
if(parent == clk->parents[i]){
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = clk->ops->set_parent(clk->hw, index);
|
||||
#endif
|
||||
if(ret)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
const struct clk_ops clkops_rate_cif_out = {
|
||||
.recalc_rate = cif_out_recalc_rate,
|
||||
.round_rate = cif_out_round_rate,
|
||||
.set_rate = cif_out_set_rate,
|
||||
};
|
||||
|
||||
static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
@@ -428,387 +296,46 @@ static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct clk_ops clkops_rate_frac = {
|
||||
.recalc_rate = clk_fracdiv_recalc,
|
||||
.round_rate = clk_fracdiv_round_rate,
|
||||
.set_rate = clk_fracdiv_set_rate,
|
||||
};
|
||||
|
||||
const struct clk_ops clkops_rate_i2s_frac = {
|
||||
.recalc_rate = clk_fracdiv_recalc,
|
||||
.round_rate = clk_fracdiv_round_rate,
|
||||
.set_rate = clk_i2s_fracdiv_set_rate,
|
||||
};
|
||||
static unsigned long clk_i2s_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return hw->clk->parent->rate;
|
||||
}
|
||||
|
||||
static long clk_i2s_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
#define I2S_SRC_DIV (0x0)
|
||||
#define I2S_SRC_FRAC (0x1)
|
||||
#define I2S_SRC_12M (0x2)
|
||||
static int clk_i2s_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
u8 p_index = 0;
|
||||
struct clk *parent_tmp, *parent;
|
||||
struct clk *clk = hw->clk;
|
||||
|
||||
|
||||
if (rate == clk->parents[I2S_SRC_12M]->rate) {
|
||||
parent = clk->parents[I2S_SRC_12M];
|
||||
p_index = I2S_SRC_12M;
|
||||
goto set_parent;
|
||||
}
|
||||
|
||||
parent_tmp = clk->parents[I2S_SRC_DIV];
|
||||
|
||||
if(parent_tmp->ops->round_rate(parent_tmp->hw, rate,
|
||||
&parent_tmp->parent->rate) == rate) {
|
||||
parent = clk->parents[I2S_SRC_DIV];
|
||||
p_index = I2S_SRC_DIV;
|
||||
goto set;
|
||||
}
|
||||
|
||||
parent = clk->parents[I2S_SRC_FRAC];
|
||||
p_index = I2S_SRC_FRAC;
|
||||
//ret = clk_set_rate(parent_tmp, parent_tmp->parent->rate);
|
||||
ret = parent_tmp->ops->set_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate,
|
||||
parent_tmp->parent->rate);
|
||||
parent_tmp->rate = parent_tmp->ops->recalc_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set:
|
||||
clk_debug(" %s set rate=%lu parent %s(old %s)\n",
|
||||
clk->name, rate, parent->name, clk->parent->name);
|
||||
|
||||
ret = clk_set_rate(parent, rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_parent:
|
||||
clk_debug("%s: set parent\n", __func__);
|
||||
if (clk->parent != parent) {
|
||||
ret = clk_set_parent(clk, parent);
|
||||
/*
|
||||
* clk->ops->set_parent(hw, p_index);
|
||||
*/
|
||||
if (ret) {
|
||||
clk_debug("%s can't get rate%lu,reparent err\n",
|
||||
clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct clk_ops clkops_rate_i2s = {
|
||||
.recalc_rate = clk_i2s_recalc_rate,
|
||||
.round_rate = clk_i2s_round_rate,
|
||||
.set_rate = clk_i2s_set_rate,
|
||||
};
|
||||
const struct clk_ops clkops_rate_hsadc_frac = {
|
||||
.recalc_rate = clk_fracdiv_recalc,
|
||||
.round_rate = clk_fracdiv_round_rate,
|
||||
.set_rate = clk_fracdiv_set_rate,
|
||||
};
|
||||
|
||||
|
||||
const struct clk_ops clkops_rate_uart_frac = {
|
||||
.recalc_rate = clk_fracdiv_recalc,
|
||||
.round_rate = clk_fracdiv_round_rate,
|
||||
.set_rate = clk_fracdiv_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long clk_uart_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return hw->clk->parent->rate;
|
||||
|
||||
}
|
||||
static long clk_uart_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
#define UART_SRC_DIV (0x0)
|
||||
#define UART_SRC_FRAC (0x1)
|
||||
#define UART_SRC_24M (0x2)
|
||||
static int clk_uart_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
u8 p_index = 0;
|
||||
struct clk *parent_tmp, *parent;
|
||||
struct clk *clk = hw->clk;
|
||||
|
||||
|
||||
if (rate == clk->parents[UART_SRC_24M]->rate) {
|
||||
parent = clk->parents[UART_SRC_24M];
|
||||
p_index = UART_SRC_24M;
|
||||
goto set_parent;
|
||||
}
|
||||
|
||||
parent_tmp = clk->parents[UART_SRC_DIV];
|
||||
|
||||
if(parent_tmp->ops->round_rate(parent_tmp->hw, rate,
|
||||
&parent_tmp->parent->rate) == rate) {
|
||||
parent = clk->parents[UART_SRC_DIV];
|
||||
p_index = UART_SRC_DIV;
|
||||
goto set;
|
||||
}
|
||||
|
||||
parent = clk->parents[UART_SRC_FRAC];
|
||||
p_index = UART_SRC_FRAC;
|
||||
/*
|
||||
* ret = clk_set_rate(parent_tmp, parent_tmp->parent->rate);
|
||||
*/
|
||||
ret = parent_tmp->ops->set_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate,
|
||||
parent_tmp->parent->rate);
|
||||
parent_tmp->rate = parent_tmp->ops->recalc_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set:
|
||||
clk_debug(" %s set rate=%lu parent %s(old %s)\n",
|
||||
clk->name, rate, parent->name, clk->parent->name);
|
||||
|
||||
ret = clk_set_rate(parent, rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_parent:
|
||||
clk_debug("%s: set parent\n", __func__);
|
||||
if (clk->parent != parent) {
|
||||
ret = clk_set_parent(clk, parent);
|
||||
/*
|
||||
* clk->ops->set_parent(hw, p_index);
|
||||
*/
|
||||
if (ret) {
|
||||
clk_debug("%s can't get rate%lu,reparent err\n",
|
||||
clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const struct clk_ops clkops_rate_uart = {
|
||||
.recalc_rate = clk_uart_recalc_rate,
|
||||
.round_rate = clk_uart_round_rate,
|
||||
.set_rate = clk_uart_set_rate,
|
||||
};
|
||||
|
||||
|
||||
static unsigned long clk_hsadc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return hw->clk->parent->rate;
|
||||
|
||||
}
|
||||
static long clk_hsadc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
#define HSADC_SRC_DIV (0x0)
|
||||
#define HSADC_SRC_FRAC (0x1)
|
||||
#define HSADC_SRC_EXT (0x2)
|
||||
static int clk_hsadc_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
u8 p_index = 0;
|
||||
struct clk *parent_tmp, *parent;
|
||||
struct clk *clk = hw->clk;
|
||||
|
||||
|
||||
if (rate == clk->parents[HSADC_SRC_EXT]->rate) {
|
||||
parent = clk->parents[HSADC_SRC_EXT];
|
||||
p_index = HSADC_SRC_EXT;
|
||||
goto set_parent;
|
||||
}
|
||||
|
||||
parent_tmp = clk->parents[HSADC_SRC_DIV];
|
||||
|
||||
if(parent_tmp->ops->round_rate(parent_tmp->hw, rate,
|
||||
&parent_tmp->parent->rate) == rate) {
|
||||
parent = clk->parents[HSADC_SRC_DIV];
|
||||
p_index = HSADC_SRC_DIV;
|
||||
goto set;
|
||||
}
|
||||
|
||||
parent = clk->parents[HSADC_SRC_FRAC];
|
||||
p_index = HSADC_SRC_FRAC;
|
||||
/*
|
||||
* ret = clk_set_rate(parent_tmp, parent_tmp->parent->rate);
|
||||
*/
|
||||
ret = parent_tmp->ops->set_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate,
|
||||
parent_tmp->parent->rate);
|
||||
parent_tmp->rate = parent_tmp->ops->recalc_rate(parent_tmp->hw,
|
||||
parent_tmp->parent->rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
set:
|
||||
clk_debug(" %s set rate=%lu parent %s(old %s)\n",
|
||||
clk->name, rate, parent->name, clk->parent->name);
|
||||
|
||||
ret = clk_set_rate(parent, rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_parent:
|
||||
clk_debug("%s: set parent\n", __func__);
|
||||
if (clk->parent != parent) {
|
||||
ret = clk_set_parent(clk, parent);
|
||||
/*
|
||||
* clk->ops->set_parent(hw, p_index);
|
||||
*/
|
||||
if (ret) {
|
||||
clk_debug("%s can't get rate%lu,reparent err\n",
|
||||
clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const struct clk_ops clkops_rate_hsadc = {
|
||||
.recalc_rate = clk_hsadc_recalc_rate,
|
||||
.round_rate = clk_hsadc_round_rate,
|
||||
.set_rate = clk_hsadc_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long clk_mac_ref_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return hw->clk->parent->rate;
|
||||
|
||||
}
|
||||
static long clk_mac_ref_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
#define MAC_SRC_DIV (0x0)
|
||||
#define RMII_CLKIN (0x1)
|
||||
static int clk_mac_ref_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
u8 p_index = 0;
|
||||
struct clk *parent;
|
||||
struct clk *clk = hw->clk;
|
||||
|
||||
clk_debug("%s: rate %lu\n", __func__, rate);
|
||||
|
||||
if (rate == clk->parents[RMII_CLKIN]->rate) {
|
||||
parent = clk->parents[RMII_CLKIN];
|
||||
p_index = RMII_CLKIN;
|
||||
goto set_parent;
|
||||
}
|
||||
|
||||
parent = clk->parents[MAC_SRC_DIV];
|
||||
p_index = MAC_SRC_DIV;
|
||||
|
||||
clk_debug(" %s set rate=%lu parent %s(old %s)\n",
|
||||
clk->name, rate, parent->name, clk->parent->name);
|
||||
|
||||
/*
|
||||
* ret = clk_set_rate(parent, rate);
|
||||
*/
|
||||
ret = parent->ops->set_rate(parent->hw,
|
||||
rate,
|
||||
parent->parent->rate);
|
||||
parent->rate = parent->ops->recalc_rate(parent->hw,
|
||||
parent->parent->rate);
|
||||
//ret = parent->ops->set_rate(parent->hw, rate, parent->parent->rate);
|
||||
if (ret) {
|
||||
clk_debug("%s set rate%lu err\n", clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_parent:
|
||||
clk_debug("%s: set parent\n", __func__);
|
||||
if (clk->parent != parent) {
|
||||
ret = clk_set_parent(clk, parent);
|
||||
/*
|
||||
* clk->ops->set_parent(hw, p_index);
|
||||
*/
|
||||
if (ret) {
|
||||
clk_debug("%s can't get rate%lu,reparent err\n",
|
||||
clk->name, rate);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const struct clk_ops clkops_rate_mac_ref = {
|
||||
.recalc_rate = clk_mac_ref_recalc_rate,
|
||||
.round_rate = clk_mac_ref_round_rate,
|
||||
.set_rate = clk_mac_ref_set_rate,
|
||||
};
|
||||
|
||||
|
||||
struct clk_ops_table rk_clkops_rate_table[] = {
|
||||
{.index = CLKOPS_RATE_MUX_DIV, .clk_ops = &clkops_rate_auto_parent},
|
||||
{.index = CLKOPS_RATE_EVENDIV, .clk_ops = &clkops_rate_evendiv},
|
||||
{.index = CLKOPS_RATE_DCLK_LCDC, .clk_ops = &clkops_rate_dclk_lcdc},
|
||||
{.index = CLKOPS_RATE_CIFOUT, .clk_ops = &clkops_rate_cif_out},
|
||||
{.index = CLKOPS_RATE_I2S_FRAC, .clk_ops = &clkops_rate_i2s_frac},
|
||||
{.index = CLKOPS_RATE_I2S, .clk_ops = &clkops_rate_i2s},
|
||||
{.index = CLKOPS_RATE_HSADC_FRAC, .clk_ops = &clkops_rate_hsadc_frac},
|
||||
{.index = CLKOPS_RATE_UART_FRAC, .clk_ops = &clkops_rate_uart_frac},
|
||||
{.index = CLKOPS_RATE_UART, .clk_ops = &clkops_rate_uart},
|
||||
{.index = CLKOPS_RATE_HSADC, .clk_ops = &clkops_rate_hsadc},
|
||||
{.index = CLKOPS_RATE_MAC_REF, .clk_ops = &clkops_rate_mac_ref},
|
||||
|
||||
|
||||
{.index = CLKOPS_TABLE_END},
|
||||
{.index = CLKOPS_RATE_FRAC, .clk_ops = &clkops_rate_frac},
|
||||
{.index = CLKOPS_RATE_I2S, .clk_ops = NULL},
|
||||
{.index = CLKOPS_RATE_CIFOUT, .clk_ops = NULL},
|
||||
{.index = CLKOPS_RATE_UART, .clk_ops = NULL},
|
||||
{.index = CLKOPS_RATE_HSADC, .clk_ops = NULL},
|
||||
{.index = CLKOPS_RATE_MAC_REF, .clk_ops = NULL},
|
||||
{.index = CLKOPS_TABLE_END, .clk_ops = NULL},
|
||||
};
|
||||
const struct clk_ops *rk_get_clkops(u32 idx)
|
||||
|
||||
const struct clk_ops *rk_get_clkops(unsigned int idx)
|
||||
{
|
||||
return rk_clkops_rate_table[idx].clk_ops;
|
||||
int i = 0;
|
||||
unsigned int now_idx;
|
||||
|
||||
while(1){
|
||||
now_idx = rk_clkops_rate_table[i].index;
|
||||
|
||||
if ((now_idx == idx) || (now_idx == CLKOPS_TABLE_END))
|
||||
return rk_clkops_rate_table[i].clk_ops;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rk_get_clkops);
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#ifndef __RK_CLK_OPS_H
|
||||
#define __RK_CLK_OPS_H
|
||||
#include "clkops-dtsi.h"
|
||||
|
||||
|
||||
#define MHZ (1000UL * 1000UL)
|
||||
#define KHZ (1000UL)
|
||||
|
||||
struct clk_ops_table {
|
||||
unsigned int index;
|
||||
const struct clk_ops *clk_ops;
|
||||
};
|
||||
const struct clk_ops *rk_get_clkops(u32 idx);
|
||||
const struct clk_ops *rk_get_clkops(unsigned int idx);
|
||||
|
||||
//#define RKCLK_DEBUG
|
||||
//#define RKCLK_TEST
|
||||
|
||||
#if defined(RKCLK_DEBUG)
|
||||
#define clk_debug(fmt, args...) printk(KERN_INFO "rkclk: "fmt, ##args)
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
|
||||
#define MHZ (1000UL * 1000UL)
|
||||
#define KHZ (1000UL)
|
||||
#define CLK_LOOPS_JIFFY_REF (11996091ULL)
|
||||
#define CLK_LOOPS_RATE_REF (1200UL) //Mhz
|
||||
#define CLK_LOOPS_RECALC(rate) \
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#include "clk-pll.h"
|
||||
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
struct rkclk_divmap_table {
|
||||
u32 reg_val;
|
||||
u32 div_val;
|
||||
@@ -53,6 +51,7 @@ struct rkclk_muxinfo {
|
||||
u32 width;
|
||||
u32 parent_num;
|
||||
u32 clkops_idx;
|
||||
u32 flags;
|
||||
const char *clk_name;
|
||||
const char **parent_names;
|
||||
struct list_head node;
|
||||
@@ -108,8 +107,10 @@ struct rkclk {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
LIST_HEAD(rk_clks);
|
||||
void __iomem *reg_start = 0;
|
||||
|
||||
#define RKCLK_PLL_TYPE (1 << 0)
|
||||
#define RKCLK_MUX_TYPE (1 << 1)
|
||||
#define RKCLK_DIV_TYPE (1 << 2)
|
||||
@@ -132,6 +133,11 @@ static int rkclk_init_muxinfo(struct device_node *np,
|
||||
ret = of_property_read_u32_index(np, "rockchip,bits", 0, &mux->shift);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_read_u32(np, "rockchip,flags", &mux->flags);
|
||||
if (ret != 0)
|
||||
mux->flags = 0;
|
||||
|
||||
ret = of_property_read_u32(np, "rockchip,clkops-idx", &mux->clkops_idx);
|
||||
if (ret != 0)
|
||||
mux->clkops_idx = CLKOPS_TABLE_END;
|
||||
@@ -186,6 +192,7 @@ static int rkclk_init_muxinfo(struct device_node *np,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkclk_init_divinfo(struct device_node *np,
|
||||
struct rkclk_divinfo *div, void __iomem *addr)
|
||||
{
|
||||
@@ -202,6 +209,7 @@ static int rkclk_init_divinfo(struct device_node *np,
|
||||
div->addr = addr;
|
||||
|
||||
of_property_read_u32(np, "rockchip,div-type", &div->div_type);
|
||||
|
||||
ret = of_property_read_u32(np, "rockchip,clkops-idx", &div->clkops_idx);
|
||||
if (ret != 0)
|
||||
div->clkops_idx = CLKOPS_TABLE_END;
|
||||
@@ -276,6 +284,7 @@ static int rkclk_init_divinfo(struct device_node *np,
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int rkclk_init_fracinfo(struct device_node *np,
|
||||
struct rkclk_fracinfo *frac, void __iomem *addr)
|
||||
{
|
||||
@@ -448,6 +457,7 @@ static int __init rkclk_init_gatecon(struct device_node *np)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init rkclk_init_pllcon(struct device_node *np)
|
||||
{
|
||||
struct rkclk_pllinfo *pllinfo;
|
||||
@@ -529,27 +539,6 @@ static int __init rkclk_init_pllcon(struct device_node *np)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return parent_rate;
|
||||
}
|
||||
static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const struct clk_ops clk_frac_ops = {
|
||||
.recalc_rate = clk_frac_recalc_rate,
|
||||
.round_rate = clk_frac_round_rate,
|
||||
.set_rate = clk_frac_set_rate,
|
||||
};
|
||||
static unsigned long clk_div_special_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
@@ -565,12 +554,14 @@ static int clk_div_special_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// For fixed div clks and For user defined div clk
|
||||
const struct clk_ops clk_div_special_ops = {
|
||||
.recalc_rate = clk_div_special_recalc_rate,
|
||||
.round_rate = clk_div_special_round_rate,
|
||||
.set_rate = clk_div_special_set_rate,
|
||||
};
|
||||
|
||||
static int rkclk_register(struct rkclk *rkclk)
|
||||
{
|
||||
struct clk_mux *mux = NULL;
|
||||
@@ -586,9 +577,11 @@ static int rkclk_register(struct rkclk *rkclk)
|
||||
struct clk_hw *rate_hw;
|
||||
int parent_num;
|
||||
struct device_node *node = rkclk->np;
|
||||
/* Single clk */
|
||||
clk_debug("%s: %s clk_type=%x\n", __func__,
|
||||
rkclk->clk_name, rkclk->clk_type);
|
||||
unsigned long flags = 0;
|
||||
|
||||
|
||||
clk_debug("%s >>>>>start: clk_name=%s, clk_type=%x\n",
|
||||
__func__, rkclk->clk_name, rkclk->clk_type);
|
||||
|
||||
if (rkclk->clk_type & RKCLK_PLL_TYPE) {
|
||||
pll = kzalloc(sizeof(struct clk_pll), GFP_KERNEL);
|
||||
@@ -604,19 +597,19 @@ static int rkclk_register(struct rkclk *rkclk)
|
||||
|
||||
} else if (rkclk->clk_type & RKCLK_FRAC_TYPE) {
|
||||
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
|
||||
if (rkclk->frac_info->clkops_idx != CLKOPS_TABLE_END)
|
||||
rate_ops = rk_get_clkops(rkclk->frac_info->clkops_idx);
|
||||
else
|
||||
rate_ops = &clk_frac_ops;
|
||||
div->reg = rkclk->frac_info->addr;
|
||||
div->shift = (u8)rkclk->frac_info->shift;
|
||||
div->width = rkclk->frac_info->width;
|
||||
div->flags = CLK_DIVIDER_HIWORD_MASK;
|
||||
|
||||
rate_hw = &div->hw;
|
||||
rate_ops = rk_get_clkops(rkclk->frac_info->clkops_idx);
|
||||
|
||||
parent_num = 1;
|
||||
parent_names = &rkclk->frac_info->parent_name;
|
||||
|
||||
flags |= CLK_SET_RATE_PARENT;
|
||||
|
||||
} else if (rkclk->clk_type & RKCLK_DIV_TYPE) {
|
||||
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
|
||||
if (rkclk->div_info->clkops_idx != CLKOPS_TABLE_END)
|
||||
@@ -655,6 +648,7 @@ static int rkclk_register(struct rkclk *rkclk)
|
||||
|
||||
parent_num = rkclk->mux_info->parent_num;
|
||||
parent_names = rkclk->mux_info->parent_names;
|
||||
flags |= rkclk->mux_info->flags;
|
||||
}
|
||||
|
||||
if (rkclk->clk_type & RKCLK_GATE_TYPE) {
|
||||
@@ -668,46 +662,43 @@ static int rkclk_register(struct rkclk *rkclk)
|
||||
// FIXME: flag(CLK_IGNORE_UNUSED) may need an input argument
|
||||
if (rkclk->clk_type == RKCLK_MUX_TYPE
|
||||
&& rkclk->mux_info->clkops_idx == CLKOPS_TABLE_END) {
|
||||
clk_debug("use clk_register_mux\n");
|
||||
clk = clk_register_mux(NULL, rkclk->clk_name,
|
||||
rkclk->mux_info->parent_names,
|
||||
(u8)rkclk->mux_info->parent_num,
|
||||
CLK_SET_RATE_PARENT,
|
||||
mux->reg, mux->shift, mux->mask,
|
||||
flags, mux->reg, mux->shift, mux->mask,
|
||||
0, &clk_lock);
|
||||
} else if (rkclk->clk_type == RKCLK_DIV_TYPE) {
|
||||
clk_debug("use clk_register_divider\n");
|
||||
clk = clk_register_divider(NULL, rkclk->clk_name,
|
||||
rkclk->div_info->parent_name,
|
||||
CLK_SET_RATE_PARENT, div->reg, div->shift,
|
||||
flags, div->reg, div->shift,
|
||||
div->width, div->flags, &clk_lock);
|
||||
} else if (rkclk->clk_type == RKCLK_GATE_TYPE) {
|
||||
clk_debug("use clk_register_gate\n");
|
||||
clk = clk_register_gate(NULL, rkclk->clk_name,
|
||||
rkclk->gate_info->parent_name,
|
||||
CLK_IGNORE_UNUSED, gate->reg,
|
||||
flags, gate->reg,
|
||||
gate->bit_idx,
|
||||
gate->flags, &clk_lock);
|
||||
} else if (rkclk->clk_type == RKCLK_PLL_TYPE) {
|
||||
clk_debug("use rk_clk_register_pll\n");
|
||||
clk = rk_clk_register_pll(NULL, rkclk->clk_name,
|
||||
rkclk->pll_info->parent_name,
|
||||
0, pll->reg, pll->width, pll->id,
|
||||
&clk_lock);
|
||||
flags, pll->reg, pll->width,
|
||||
pll->id, &clk_lock);
|
||||
} else {
|
||||
int i = 0;
|
||||
clk_debug("%s: composite clk(\"%s\") parents:\n",
|
||||
__func__, rkclk->clk_name);
|
||||
|
||||
for (i = 0; i < parent_num; i++) {
|
||||
clk_debug("\t\t%s: parent[%d]=%s\n", __func__,
|
||||
i, parent_names[i]);
|
||||
}
|
||||
|
||||
clk_debug("use clk_register_composite\n");
|
||||
clk = clk_register_composite(NULL, rkclk->clk_name,
|
||||
parent_names, parent_num,
|
||||
mux ? &mux->hw : NULL, mux ? mux_ops : NULL,
|
||||
rate_hw, rate_ops,
|
||||
gate ? &gate->hw : NULL, gate ? &clk_gate_ops : NULL,
|
||||
CLK_IGNORE_UNUSED);
|
||||
flags);
|
||||
}
|
||||
|
||||
if (clk) {
|
||||
clk_debug("clk name=%s, flags=0x%lx\n", clk->name, clk->flags);
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
clk_register_clkdev(clk, rkclk->clk_name, NULL);
|
||||
} else {
|
||||
@@ -718,39 +709,51 @@ static int rkclk_register(struct rkclk *rkclk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RKCLK_TEST
|
||||
struct test_table {
|
||||
const char *name;
|
||||
u32 rate;
|
||||
};
|
||||
|
||||
struct test_table t_table[] = {
|
||||
{.name = "clk_gpu", .rate = 297000000},
|
||||
{.name = "dclk_lcdc0", .rate = 297000000},
|
||||
{.name = "clk_i2s", .rate = 11289600},
|
||||
{.name = "clk_spdif", .rate = 11289600},
|
||||
{.name = "dclk_lcdc0", .rate = 100000000},
|
||||
{.name = "aclk_lcdc0", .rate = 297000000},
|
||||
|
||||
{.name = "clk_sdmmc", .rate = 50000000},
|
||||
{.name = "clk_emmc", .rate = 50000000},
|
||||
{.name = "clk_sdio", .rate = 50000000},
|
||||
|
||||
{.name = "clk_i2s_div", .rate = 300000000},
|
||||
{.name = "clk_i2s_frac",.rate = 22579200},
|
||||
{.name = "clk_i2s", .rate = 11289600},
|
||||
{.name = "clk_spdif", .rate = 11289600},
|
||||
|
||||
{.name = "cif_out_pll", .rate = 48000000},
|
||||
{.name = "clk_cif0", .rate = 12000000},
|
||||
|
||||
{.name = "clk_uart0", .rate = 12288000},
|
||||
{.name = "clk_uart1", .rate = 48000000},
|
||||
{.name = "clk_hsadc", .rate = 12288000},
|
||||
{.name = "clk_mac", .rate = 50000000},
|
||||
{.name = "clk_cif0", .rate = 12000000},
|
||||
{.name = "aclk_lcdc0", .rate = 297000000},
|
||||
{.name = "clk_apll", .rate = 600000000},
|
||||
{.name = "clk_dpll", .rate = 600000000},
|
||||
|
||||
{.name = "clk_apll", .rate = 500000000},
|
||||
{.name = "clk_dpll", .rate = 400000000},
|
||||
{.name = "clk_cpll", .rate = 600000000},
|
||||
{.name = "clk_gpll", .rate = 800000000},
|
||||
};
|
||||
|
||||
|
||||
#ifdef RKCLK_DEBUG
|
||||
void rk_clk_test(void)
|
||||
{
|
||||
const char *clk_name;
|
||||
struct clk *clk;
|
||||
u32 rate,recalc_rate,round_rate = 0;
|
||||
|
||||
unsigned long rate=0, recalc_rate=0, round_rate=0, get_rate=0;
|
||||
u32 i = 0, j = 0;
|
||||
int ret;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(t_table); j++) {
|
||||
clk_debug(">>>>>>test %u\n", j);
|
||||
|
||||
clk_name = t_table[j].name;
|
||||
rate = t_table[j].rate;
|
||||
|
||||
@@ -760,55 +763,50 @@ void rk_clk_test(void)
|
||||
__func__, clk_name);
|
||||
} else
|
||||
clk_debug("%s: clk(\"%s\") \tclk_get success\n",
|
||||
__func__, __clk_get_name(clk));
|
||||
__func__, clk_name);
|
||||
|
||||
/*TEST: clk_round_rate*/
|
||||
if (clk->ops->round_rate) {
|
||||
round_rate = clk_round_rate(clk, rate);
|
||||
clk_debug("%s: clk(\"%s\") \tclk_round_rate from %lu to %lu\n",
|
||||
__func__, __clk_get_name(clk),
|
||||
rate, round_rate);
|
||||
} else {
|
||||
clk_debug("%s: clk(\"%s\") have no round ops\n",
|
||||
__func__, clk->name);
|
||||
}
|
||||
/* TEST: clk_round_rate */
|
||||
round_rate = clk_round_rate(clk, rate);
|
||||
clk_debug("%s: clk(\"%s\") \tclk_round_rate from %lu to %lu\n",
|
||||
__func__, clk_name, rate, round_rate);
|
||||
|
||||
/* TEST: clk_set_rate */
|
||||
if (clk->ops->set_rate) {
|
||||
if (0 != clk_set_rate(clk, rate)) {
|
||||
clk_err("%s: clk(\"%s\") \tclk_set_rate error\n",
|
||||
__func__, clk_name);
|
||||
} else {
|
||||
clk_debug("%s: clk(\"%s\") \tclk_set_rate success\n",
|
||||
__func__, __clk_get_name(clk));
|
||||
}
|
||||
ret = clk_set_rate(clk, rate);
|
||||
if (ret) {
|
||||
clk_err("%s: clk(\"%s\") \tclk_set_rate error, ret=%d\n",
|
||||
__func__, clk_name, ret);
|
||||
} else {
|
||||
clk_debug("%s: clk(\"%s\") have no set ops\n",
|
||||
__func__, clk->name);
|
||||
clk_debug("%s: clk(\"%s\") \tclk_set_rate success\n",
|
||||
__func__, clk_name);
|
||||
}
|
||||
|
||||
/*TEST: clk_recalc_rate*/
|
||||
/* TEST: recalc_rate\clk_get_rate */
|
||||
if (clk->ops->recalc_rate) {
|
||||
recalc_rate = clk->ops->recalc_rate(clk->hw,
|
||||
clk->parent->rate);
|
||||
clk->parent->rate);
|
||||
clk_debug("%s: clk(\"%s\") \tclk_recalc_rate %lu\n",
|
||||
__func__, __clk_get_name(clk),
|
||||
recalc_rate);
|
||||
__func__, clk_name, recalc_rate);
|
||||
} else {
|
||||
clk_debug("%s: clk(\"%s\") have no recalc ops\n",
|
||||
__func__, clk->name);
|
||||
__func__, clk_name);
|
||||
get_rate = clk_get_rate(clk);
|
||||
clk_debug("%s: clk(\"%s\") \tclk_get_rate %lu\n",
|
||||
__func__, clk_name, get_rate);
|
||||
}
|
||||
|
||||
}
|
||||
#if 0
|
||||
printk("\n");
|
||||
printk("dump cru regs:");
|
||||
for (i = 0; i * 4 <= 0xf4; i++) {
|
||||
if (i % 4 == 0)
|
||||
printk("\n%s: \t[0x%08x]: ",
|
||||
__func__, 0x20000000 + i * 4);
|
||||
printk("%08x ", readl(reg_start + i * 4));
|
||||
}
|
||||
printk("\n\n");
|
||||
|
||||
printk("dump cru regs:\n");
|
||||
for (i = 0; i * 4 <= 0xf4; i++) {
|
||||
if (i % 4 == 0)
|
||||
printk("\n%s: \t[0x%08x]: ",
|
||||
__func__, 0x20000000 + i * 4);
|
||||
printk("%08x ", readl(reg_start + i * 4));
|
||||
#endif
|
||||
}
|
||||
printk("\n\n");
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rk_clk_test);
|
||||
@@ -816,28 +814,23 @@ EXPORT_SYMBOL_GPL(rk_clk_test);
|
||||
void rk_clk_test(void){};
|
||||
EXPORT_SYMBOL_GPL(rk_clk_test);
|
||||
#endif
|
||||
extern void clk_dump_tree(void);
|
||||
|
||||
|
||||
void rkclk_init_clks(struct device_node *node);
|
||||
|
||||
static void __init rk_clk_tree_init(struct device_node *np)
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
|
||||
struct device_node *node_init;
|
||||
struct rkclk *rkclk;
|
||||
|
||||
node_init=of_find_node_by_name(NULL,"clocks-init");
|
||||
if(!node_init)
|
||||
{
|
||||
printk("%s:can not get clocks-init node\n",__FUNCTION__);
|
||||
{
|
||||
printk("%s:can not get clocks-init node\n",__FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for_each_available_child_of_node(np, node) {
|
||||
|
||||
if (!ERR_PTR(of_property_match_string(node,
|
||||
@@ -875,7 +868,6 @@ static void __init rk_clk_tree_init(struct device_node *np)
|
||||
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
list_for_each_entry(rkclk, &rk_clks, node) {
|
||||
int i;
|
||||
@@ -909,12 +901,13 @@ static void __init rk_clk_tree_init(struct device_node *np)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
list_for_each_entry(rkclk, &rk_clks, node) {
|
||||
rkclk_register(rkclk);
|
||||
}
|
||||
|
||||
/* check clock parents init */
|
||||
list_for_each_entry(rkclk, &rk_clks, node) {
|
||||
|
||||
struct clk *clk;
|
||||
int i = 0;
|
||||
const char *clk_name = rkclk->clk_name;
|
||||
@@ -950,9 +943,10 @@ static void __init rk_clk_tree_init(struct device_node *np)
|
||||
rkclk_init_clks(node_init);
|
||||
|
||||
}
|
||||
CLK_OF_DECLARE(rk_clocks, "rockchip,rk-clock-regs", rk_clk_tree_init);
|
||||
CLK_OF_DECLARE(rk_clocks, "rockchip,rk-clock-regs", rk_clk_tree_init);
|
||||
|
||||
/********************************** rock chip clks init****************************************/
|
||||
|
||||
/********************************** rockchip clks init****************************************/
|
||||
const char *of_clk_init_rate_get_info(struct device_node *np, int index,u32 *rate)
|
||||
{
|
||||
struct of_phandle_args clkspec;
|
||||
@@ -963,15 +957,15 @@ const char *of_clk_init_rate_get_info(struct device_node *np, int index,u32 *rat
|
||||
return NULL;
|
||||
|
||||
rc = of_parse_phandle_with_args(np, "rockchip,clocks-init-rate", "#clock-init-cells", index,
|
||||
&clkspec);
|
||||
&clkspec);
|
||||
if (rc)
|
||||
return NULL;
|
||||
|
||||
if (of_property_read_string_index(clkspec.np, "clock-output-names",0,&clk_name) < 0)
|
||||
return NULL;
|
||||
|
||||
|
||||
*rate= clkspec.args[0];
|
||||
|
||||
|
||||
of_node_put(clkspec.np);
|
||||
return clk_name;
|
||||
}
|
||||
@@ -988,14 +982,14 @@ const char *of_clk_init_parent_get_info(struct device_node *np, int index,const
|
||||
return NULL;
|
||||
|
||||
rc = of_parse_phandle_with_args(np, "rockchip,clocks-init-parent", "#clock-init-cells", index,
|
||||
&clkspec);
|
||||
&clkspec);
|
||||
if (rc)
|
||||
return NULL;
|
||||
|
||||
if (of_property_read_string_index(clkspec.np, "clock-output-names",0,&clk_name) < 0)
|
||||
return NULL;
|
||||
|
||||
|
||||
|
||||
phandle = clkspec.args[0];
|
||||
|
||||
of_node_put(clkspec.np);
|
||||
@@ -1006,21 +1000,21 @@ const char *of_clk_init_parent_get_info(struct device_node *np, int index,const
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (of_property_read_string_index(node, "clock-output-names",0,clk_child_name) < 0)
|
||||
return NULL;
|
||||
|
||||
|
||||
of_node_put(node);//???
|
||||
node=NULL;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
|
||||
return clk_name;
|
||||
}
|
||||
|
||||
void rkclk_init_clks(struct device_node *np)
|
||||
{
|
||||
{
|
||||
//struct device_node *np;
|
||||
int i,cnt_parent,cnt_rate;
|
||||
u32 clk_rate;
|
||||
@@ -1031,36 +1025,36 @@ void rkclk_init_clks(struct device_node *np)
|
||||
|
||||
|
||||
cnt_parent = of_count_phandle_with_args(np, "rockchip,clocks-init-parent", "#clock-init-cells");
|
||||
|
||||
printk("%s:cnt_parent =%d\n",__FUNCTION__,cnt_parent);
|
||||
|
||||
printk("%s:cnt_parent =%d\n",__FUNCTION__,cnt_parent);
|
||||
|
||||
|
||||
for (i = 0; i < cnt_parent; i++) {
|
||||
clk_parent_name=NULL;
|
||||
clk_name=of_clk_init_parent_get_info(np, i,&clk_parent_name);
|
||||
|
||||
|
||||
if(clk_name==NULL||clk_parent_name==NULL)
|
||||
continue;
|
||||
|
||||
|
||||
clk_c=clk_get(NULL,clk_name);
|
||||
clk_p=clk_get(NULL,clk_parent_name);
|
||||
|
||||
printk("%s: set parent %s=%x,%s=%x\n",__FUNCTION__,clk_name,(u32)clk_c,clk_parent_name,(u32)clk_p);
|
||||
if(IS_ERR(clk_c)||IS_ERR(clk_p))
|
||||
if(IS_ERR(clk_c)||IS_ERR(clk_p))
|
||||
continue;
|
||||
//clk_set_parent(clk_name, clk_parent_name);
|
||||
}
|
||||
|
||||
cnt_rate = of_count_phandle_with_args(np, "rockchip,clocks-init-rate", "#clock-init-cells");
|
||||
|
||||
printk("%s:rate cnt=%d\n",__FUNCTION__,cnt_rate);
|
||||
printk("%s:rate cnt=%d\n",__FUNCTION__,cnt_rate);
|
||||
|
||||
for (i = 0; i < cnt_rate; i++) {
|
||||
clk_name=of_clk_init_rate_get_info(np, i,&clk_rate);
|
||||
|
||||
|
||||
if(clk_name==NULL)
|
||||
continue;
|
||||
|
||||
|
||||
clk_p=clk_get(NULL,clk_name);
|
||||
|
||||
printk("%s: set rate %s=%x,rate=%d\n",__FUNCTION__,clk_name,(u32)clk_p,clk_rate);
|
||||
@@ -1068,12 +1062,8 @@ void rkclk_init_clks(struct device_node *np)
|
||||
if(IS_ERR(clk_c)||(clk_rate<1*1000*1000)||(clk_rate>2000*1000*1000))
|
||||
continue;
|
||||
//clk_set_rate(clk_p,clk_rate);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,20 +9,19 @@
|
||||
#define GPLL_ID 3
|
||||
|
||||
|
||||
|
||||
/* rate_ops index */
|
||||
#define CLKOPS_RATE_MUX_DIV 0
|
||||
#define CLKOPS_RATE_EVENDIV 1
|
||||
#define CLKOPS_RATE_DCLK_LCDC 2
|
||||
#define CLKOPS_RATE_CIFOUT 3
|
||||
#define CLKOPS_RATE_I2S_FRAC 4
|
||||
#define CLKOPS_RATE_I2S_FRAC 3
|
||||
#define CLKOPS_RATE_FRAC 4
|
||||
#define CLKOPS_RATE_I2S 5
|
||||
#define CLKOPS_RATE_HSADC_FRAC 6
|
||||
#define CLKOPS_RATE_UART_FRAC 7
|
||||
#define CLKOPS_RATE_UART 8
|
||||
#define CLKOPS_RATE_HSADC 9
|
||||
#define CLKOPS_RATE_MAC_REF 10
|
||||
#define CLKOPS_TABLE_END ~0
|
||||
#define CLKOPS_RATE_CIFOUT 6
|
||||
#define CLKOPS_RATE_UART 7
|
||||
#define CLKOPS_RATE_HSADC 8
|
||||
#define CLKOPS_RATE_MAC_REF 9
|
||||
#define CLKOPS_TABLE_END (~0)
|
||||
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(nr) (1 << (nr))
|
||||
@@ -37,4 +36,20 @@
|
||||
#define CLK_DIVIDER_USER_DEFINE BIT(7)
|
||||
/* CLK_DIVIDER_MASK defined the bits been used above */
|
||||
#define CLK_DIVIDER_MASK (0xFF)
|
||||
|
||||
|
||||
/*
|
||||
* flags used across common struct clk. these flags should only affect the
|
||||
* top-level framework. custom flags for dealing with hardware specifics
|
||||
* belong in struct clk_foo
|
||||
*/
|
||||
#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */
|
||||
#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */
|
||||
#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
|
||||
#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
|
||||
#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
|
||||
#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
|
||||
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
|
||||
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
|
||||
|
||||
#endif /* __RK_CLKOPS_H */
|
||||
|
||||
Reference in New Issue
Block a user