#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;
__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;
}
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;
}
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;
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;
- }
- }
+ struct clk *clk = hw->clk;
+ struct clk *parent = clk->parent;
+ long rate_out;
- 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);
- }
+ //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;
- return best_rate;
+ return rate_out;
}
-static struct clk *clk_get_best_parent(struct clk_hw *hw, unsigned long rate,
- unsigned int *div_out)
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
- 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;
-
- memset(div, 0, sizeof(div));
- memset(new_rate, 0, sizeof(new_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];
+ return clk_divider_ops.recalc_rate(hw, parent_rate);
}
-static long clk_div_round_rate_autosel_parents(struct clk_hw *hw,
+static long clk_divider_round_rate(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;
+ return clk_divider_ops.round_rate(hw, rate, prate);
}
-
-static int clk_div_set_rate_autosel_parents(struct clk_hw *hw,
+static int clk_divider_set_rate(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)
+ 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;
+ }
- 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;
+ /* 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;
}
- old_div = (clk->parent->rate)/(clk->rate);
+ /* 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;
- 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;
- }
+ parent_rate = __clk_get_rate(parent);
+ now = clk_divider_ops.round_rate(div_hw, rate, &parent_rate);
- if(clk->parent != new_parent){
- for(i=0; i<clk->num_parents; i++){
- if(new_parent == clk->parents[i]){
- index = i;
- break;
- }
+ if (now <= rate && now > best) {
+ best_parent = parent;
+ best_prate = parent_rate;
+ best = now;
}
- /*
- * 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;
-}
+ if(best_prate)
+ *best_parent_rate = best_prate;
-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);
+ 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,
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 = {
{
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;
}
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)
{
}
return 0;
}
+#endif
-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 = {
+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_uart_frac = {
+const struct clk_ops clkops_rate_i2s_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);
#include "clk-pll.h"
-static DEFINE_SPINLOCK(clk_lock);
-
struct rkclk_divmap_table {
u32 reg_val;
u32 div_val;
u32 width;
u32 parent_num;
u32 clkops_idx;
+ u32 flags;
const char *clk_name;
const char **parent_names;
struct list_head node;
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)
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;
}
return 0;
}
+
static int rkclk_init_divinfo(struct device_node *np,
struct rkclk_divinfo *div, void __iomem *addr)
{
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;
}
+
static int rkclk_init_fracinfo(struct device_node *np,
struct rkclk_fracinfo *frac, void __iomem *addr)
{
}
return 0;
}
+
static int __init rkclk_init_pllcon(struct device_node *np)
{
struct rkclk_pllinfo *pllinfo;
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)
{
{
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;
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);
} 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)
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) {
// 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 {
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;
__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);
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,
};
-
#if 0
list_for_each_entry(rkclk, &rk_clks, node) {
int i;
}
}
#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;
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;
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;
}
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);
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;
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);
if(IS_ERR(clk_c)||(clk_rate<1*1000*1000)||(clk_rate>2000*1000*1000))
continue;
//clk_set_rate(clk_p,clk_rate);
-
- }
-
-}
-
-
+ }
+}