diff options
Diffstat (limited to 'drivers/clk/msm/clock-local2.c')
| -rw-r--r-- | drivers/clk/msm/clock-local2.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c index 55fa76046def..6cf53c78d4d6 100644 --- a/drivers/clk/msm/clock-local2.c +++ b/drivers/clk/msm/clock-local2.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/spinlock.h> #include <linux/delay.h> +#include <linux/rational.h> #include <linux/clk.h> #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> @@ -1735,6 +1736,46 @@ static struct clk *edp_clk_get_parent(struct clk *c) return freq->src_clk; } +static int rcg_clk_set_rate_dp(struct clk *clk, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk_freq_tbl *freq_tbl = rcg->current_freq; + unsigned long src_rate; + unsigned long num, den, flags; + + src_rate = clk_get_rate(clk->parent); + if (src_rate <= 0) { + pr_err("Invalid RCG parent rate\n"); + return -EINVAL; + } + + rational_best_approximation(src_rate, rate, + (unsigned long)(1 << 16) - 1, + (unsigned long)(1 << 16) - 1, &den, &num); + + if (!num || !den) { + pr_err("Invalid MN values derived for requested rate %lu\n", + rate); + return -EINVAL; + } + + freq_tbl->div_src_val &= ~BM(4, 0); + if (num == den) { + freq_tbl->m_val = 0; + freq_tbl->n_val = 0; + } else { + freq_tbl->m_val = num; + freq_tbl->n_val = ~(den - num); + freq_tbl->d_val = ~den; + } + + spin_lock_irqsave(&local_clock_reg_lock, flags); + if (!is_same_rcg_config(rcg, freq_tbl, true)) + __set_rate_mnd(rcg, freq_tbl); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return 0; +} + static int gate_clk_enable(struct clk *c) { unsigned long flags; @@ -2291,6 +2332,15 @@ struct clk_ops clk_ops_rcg_edp = { .list_registers = rcg_hid_clk_list_registers, }; +struct clk_ops clk_ops_rcg_dp = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate_dp, + .list_rate = rcg_clk_list_rate, + .handoff = pixel_rcg_handoff, + .list_registers = rcg_mnd_clk_list_registers, +}; + struct clk_ops clk_ops_branch = { .enable = branch_clk_enable, .prepare = branch_clk_prepare, |
