@@ -546,6 +546,153 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
546
546
return 0 ;
547
547
}
548
548
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
+
549
696
/* DPLL autoidle read/set code */
550
697
551
698
/**
0 commit comments