static int clk_fracdiv_get_config(unsigned long rate_out, unsigned long rate, u32 *numerator, u32 *denominator) { u32 gcd_val; gcd_val = clk_gcd(rate, rate_out); clk_debug("%s: frac_get_seting rate=%lu, parent=%lu, gcd=%d\n", __func__, rate_out, rate, gcd_val); if (!gcd_val) { clk_err("gcd=0, frac div is not be supported\n"); return -EINVAL; } *numerator = rate_out / gcd_val; *denominator = rate / gcd_val; clk_debug("%s: frac_get_seting numerator=%d, denominator=%d, times=%d\n", __func__, *numerator, *denominator, *denominator / *numerator); if (*numerator > 0xffff || *denominator > 0xffff || (*denominator / (*numerator)) < 20) { clk_err("can't get a available nume and deno\n"); return -EINVAL; } return 0; }
static int clk_ddr_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk *parent = __clk_get_parent(hw->clk); struct clk *grand_p = __clk_get_parent(parent); /* Do nothing before ddr init */ if (!ddr_change_freq) return 0; if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) { clk_err("fail to get parent or grand_parent!\n"); return -EINVAL; } clk_debug("%s: will set rate = %lu\n", __func__, rate); /* Func provided by ddr driver */ ddr_change_freq(rate/MHZ); parent->rate = parent->ops->recalc_rate(parent->hw, __clk_get_rate(grand_p)); return 0; }
static int clk_i2s_fracdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { u32 numerator, denominator; struct clk_divider *div = to_clk_divider(hw); int i = 10; if(clk_fracdiv_get_config(rate, parent_rate, &numerator, &denominator) == 0) { while (i--) { writel((numerator - 1) << 16 | denominator, div->reg); mdelay(1); writel(numerator << 16 | denominator, div->reg); mdelay(1); } clk_debug("%s set rate=%lu,is ok\n", hw->clk->name, rate); } else { clk_err("clk_frac_div name=%s can't get rate=%lu\n", hw->clk->name, rate); return -EINVAL; } return 0; }
static int mt_golden_setting_init(void) { #if defined(CONFIG_MT_ENG_BUILD) #define GOLDEN_SETTING_BUF_SIZE (2 * PAGE_SIZE) unsigned int *buf; buf = kmalloc(GOLDEN_SETTING_BUF_SIZE, GFP_KERNEL); if (NULL != buf) { _golden_setting_init(&_golden, buf, GOLDEN_SETTING_BUF_SIZE); #ifdef CONFIG_OF _golden.phy_base = 0; _golden.io_base = 0; #endif { struct proc_dir_entry *dir = NULL; int i; const struct { const char *name; const struct file_operations *fops; } entries[] = { PROC_ENTRY(golden_test), }; dir = proc_mkdir("golden", NULL); if (!dir) { clk_err("[%s]: fail to mkdir /proc/golden\n", __func__); EXIT_FUNC(FUNC_LV_API); return -ENOMEM; } for (i = 0; i < ARRAY_SIZE(entries); i++) { if (!proc_create(entries[i].name, S_IRUGO | S_IWUSR | S_IWGRP, dir, entries[i].fops)) clk_err("[%s]: fail to mkdir /proc/golden/%s\n", __func__, entries[i].name); } } } #endif // CONFIG_MT_ENG_BUILD return 0; }
static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, struct clk **best_parent_p) { struct clk *parent = __clk_get_parent(hw->clk); if (IS_ERR_OR_NULL(parent)) { clk_err("fail to get parent!\n"); return 0; } return clk_round_rate(parent, rate); }
static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk *parent = __clk_get_parent(hw->clk); struct clk *grand_p = __clk_get_parent(parent); int ret; if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) { clk_err("fail to get parent or grand_parent!\n"); return -EINVAL; } ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p)); parent->rate = parent->ops->recalc_rate(parent->hw, __clk_get_rate(grand_p)); return ret; }
struct clk *rk_clk_register_pd(struct device *dev, const char *name, const char *parent_name, unsigned long flags, u32 pd_id, spinlock_t *lock) { struct clk_pd *pd; struct clk *clk; struct clk_init_data init; /* allocate the pd */ pd = kzalloc(sizeof(struct clk_pd), GFP_KERNEL); if (!pd) { clk_err("%s: could not allocate pd clk\n", __func__); return ERR_PTR(-ENOMEM); } init.name = name; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); if(pd_id == CLK_PD_VIRT) init.ops = &clk_pd_virt_ops; else init.ops = &clk_pd_ops; /* struct clk_pd assignments */ pd->id= pd_id; pd->lock = lock; pd->hw.init = &init; /* register the clock */ clk = clk_register(dev, &pd->hw); if (IS_ERR(clk)) kfree(pd); return clk; }