Skip to content

Commit d539efa

Browse files
Tero KristoPaul Walmsley
authored andcommitted
ARM: OMAP3: clock: add new rate changing logic support for noncore DPLLs
Currently, DPLL code hides the re-parenting within its internals, which is wrong. This needs to be exposed to the common clock code via determine_rate and set_rate_and_parent APIs. This patch adds support for these, which will be taken into use in the following patches. Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
1 parent f0d2f68 commit d539efa

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

arch/arm/mach-omap2/dpll3xxx.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,153 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
546546
return 0;
547547
}
548548

549+
/**
550+
* omap3_noncore_dpll_determine_rate - determine rate for a DPLL
551+
* @hw: pointer to the clock to determine rate for
552+
* @rate: target rate for the DPLL
553+
* @best_parent_rate: pointer for returning best parent rate
554+
* @best_parent_clk: pointer for returning best parent clock
555+
*
556+
* Determines which DPLL mode to use for reaching a desired target rate.
557+
* Checks whether the DPLL shall be in bypass or locked mode, and if
558+
* locked, calculates the M,N values for the DPLL via round-rate.
559+
* Returns a positive clock rate with success, negative error value
560+
* in failure.
561+
*/
562+
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
563+
unsigned long *best_parent_rate,
564+
struct clk **best_parent_clk)
565+
{
566+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
567+
struct dpll_data *dd;
568+
569+
if (!hw || !rate)
570+
return -EINVAL;
571+
572+
dd = clk->dpll_data;
573+
if (!dd)
574+
return -EINVAL;
575+
576+
if (__clk_get_rate(dd->clk_bypass) == rate &&
577+
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
578+
*best_parent_clk = dd->clk_bypass;
579+
} else {
580+
rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
581+
*best_parent_clk = dd->clk_ref;
582+
}
583+
584+
*best_parent_rate = rate;
585+
586+
return rate;
587+
}
588+
589+
/**
590+
* omap3_noncore_dpll_set_parent - set parent for a DPLL clock
591+
* @hw: pointer to the clock to set parent for
592+
* @index: parent index to select
593+
*
594+
* Sets parent for a DPLL clock. This sets the DPLL into bypass or
595+
* locked mode. Returns 0 with success, negative error value otherwise.
596+
*/
597+
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
598+
{
599+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
600+
int ret;
601+
602+
if (!hw)
603+
return -EINVAL;
604+
605+
if (index)
606+
ret = _omap3_noncore_dpll_bypass(clk);
607+
else
608+
ret = _omap3_noncore_dpll_lock(clk);
609+
610+
return ret;
611+
}
612+
613+
/**
614+
* omap3_noncore_dpll_set_rate_new - set rate for a DPLL clock
615+
* @hw: pointer to the clock to set parent for
616+
* @rate: target rate for the clock
617+
* @parent_rate: rate of the parent clock
618+
*
619+
* Sets rate for a DPLL clock. First checks if the clock parent is
620+
* reference clock (in bypass mode, the rate of the clock can't be
621+
* changed) and proceeds with the rate change operation. Returns 0
622+
* with success, negative error value otherwise.
623+
*/
624+
static int omap3_noncore_dpll_set_rate_new(struct clk_hw *hw,
625+
unsigned long rate,
626+
unsigned long parent_rate)
627+
{
628+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
629+
struct dpll_data *dd;
630+
u16 freqsel = 0;
631+
int ret;
632+
633+
if (!hw || !rate)
634+
return -EINVAL;
635+
636+
dd = clk->dpll_data;
637+
if (!dd)
638+
return -EINVAL;
639+
640+
if (__clk_get_parent(hw->clk) != dd->clk_ref)
641+
return -EINVAL;
642+
643+
if (dd->last_rounded_rate == 0)
644+
return -EINVAL;
645+
646+
/* Freqsel is available only on OMAP343X devices */
647+
if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
648+
freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
649+
WARN_ON(!freqsel);
650+
}
651+
652+
pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
653+
__clk_get_name(hw->clk), rate);
654+
655+
ret = omap3_noncore_dpll_program(clk, freqsel);
656+
657+
return ret;
658+
}
659+
660+
/**
661+
* omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
662+
* @hw: pointer to the clock to set rate and parent for
663+
* @rate: target rate for the DPLL
664+
* @parent_rate: clock rate of the DPLL parent
665+
* @index: new parent index for the DPLL, 0 - reference, 1 - bypass
666+
*
667+
* Sets rate and parent for a DPLL clock. If new parent is the bypass
668+
* clock, only selects the parent. Otherwise proceeds with a rate
669+
* change, as this will effectively also change the parent as the
670+
* DPLL is put into locked mode. Returns 0 with success, negative error
671+
* value otherwise.
672+
*/
673+
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
674+
unsigned long rate,
675+
unsigned long parent_rate,
676+
u8 index)
677+
{
678+
int ret;
679+
680+
if (!hw || !rate)
681+
return -EINVAL;
682+
683+
/*
684+
* clk-ref at index[0], in which case we only need to set rate,
685+
* the parent will be changed automatically with the lock sequence.
686+
* With clk-bypass case we only need to change parent.
687+
*/
688+
if (index)
689+
ret = omap3_noncore_dpll_set_parent(hw, index);
690+
else
691+
ret = omap3_noncore_dpll_set_rate_new(hw, rate, parent_rate);
692+
693+
return ret;
694+
}
695+
549696
/* DPLL autoidle read/set code */
550697

551698
/**

include/linux/clk/ti.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,17 @@ extern const struct clk_ops ti_clk_mux_ops;
254254
void omap2_init_clk_hw_omap_clocks(struct clk *clk);
255255
int omap3_noncore_dpll_enable(struct clk_hw *hw);
256256
void omap3_noncore_dpll_disable(struct clk_hw *hw);
257+
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
257258
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
258259
unsigned long parent_rate);
260+
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
261+
unsigned long rate,
262+
unsigned long parent_rate,
263+
u8 index);
264+
long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
265+
unsigned long rate,
266+
unsigned long *best_parent_rate,
267+
struct clk **best_parent_clk);
259268
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
260269
unsigned long parent_rate);
261270
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,

0 commit comments

Comments
 (0)