@@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
460
460
/* Non-CORE DPLL rate set code */
461
461
462
462
/**
463
- * omap3_noncore_dpll_set_rate - set non-core DPLL rate
464
- * @clk: struct clk * of DPLL to set
465
- * @rate: rounded target rate
463
+ * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
464
+ * @hw: pointer to the clock to determine rate for
465
+ * @rate: target rate for the DPLL
466
+ * @best_parent_rate: pointer for returning best parent rate
467
+ * @best_parent_clk: pointer for returning best parent clock
466
468
*
467
- * Set the DPLL CLKOUT to the target rate. If the DPLL can enter
468
- * low-power bypass, and the target rate is the bypass source clock
469
- * rate, then configure the DPLL for bypass. Otherwise, round the
470
- * target rate if it hasn't been done already, then program and lock
471
- * the DPLL. Returns -EINVAL upon error, or 0 upon success .
469
+ * Determines which DPLL mode to use for reaching a desired target rate.
470
+ * Checks whether the DPLL shall be in bypass or locked mode, and if
471
+ * locked, calculates the M,N values for the DPLL via round-rate.
472
+ * Returns a positive clock rate with success, negative error value
473
+ * in failure .
472
474
*/
473
- int omap3_noncore_dpll_set_rate (struct clk_hw * hw , unsigned long rate ,
474
- unsigned long parent_rate )
475
+ long omap3_noncore_dpll_determine_rate (struct clk_hw * hw , unsigned long rate ,
476
+ unsigned long * best_parent_rate ,
477
+ struct clk * * best_parent_clk )
475
478
{
476
479
struct clk_hw_omap * clk = to_clk_hw_omap (hw );
477
- struct clk * new_parent = NULL ;
478
- unsigned long rrate ;
479
- u16 freqsel = 0 ;
480
480
struct dpll_data * dd ;
481
- int ret ;
482
481
483
482
if (!hw || !rate )
484
483
return - EINVAL ;
@@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
489
488
490
489
if (__clk_get_rate (dd -> clk_bypass ) == rate &&
491
490
(dd -> modes & (1 << DPLL_LOW_POWER_BYPASS ))) {
492
- pr_debug ("%s: %s: set rate: entering bypass.\n" ,
493
- __func__ , __clk_get_name (hw -> clk ));
491
+ * best_parent_clk = dd -> clk_bypass ;
492
+ } else {
493
+ rate = omap2_dpll_round_rate (hw , rate , best_parent_rate );
494
+ * best_parent_clk = dd -> clk_ref ;
495
+ }
496
+
497
+ * best_parent_rate = rate ;
498
+
499
+ return rate ;
500
+ }
501
+
502
+ /**
503
+ * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
504
+ * @hw: pointer to the clock to set parent for
505
+ * @index: parent index to select
506
+ *
507
+ * Sets parent for a DPLL clock. This sets the DPLL into bypass or
508
+ * locked mode. Returns 0 with success, negative error value otherwise.
509
+ */
510
+ int omap3_noncore_dpll_set_parent (struct clk_hw * hw , u8 index )
511
+ {
512
+ struct clk_hw_omap * clk = to_clk_hw_omap (hw );
513
+ int ret ;
494
514
495
- __clk_prepare (dd -> clk_bypass );
496
- clk_enable (dd -> clk_bypass );
515
+ if (!hw )
516
+ return - EINVAL ;
517
+
518
+ if (index )
497
519
ret = _omap3_noncore_dpll_bypass (clk );
498
- if (!ret )
499
- new_parent = dd -> clk_bypass ;
500
- clk_disable (dd -> clk_bypass );
501
- __clk_unprepare (dd -> clk_bypass );
502
- } else {
503
- __clk_prepare (dd -> clk_ref );
504
- clk_enable (dd -> clk_ref );
505
-
506
- /* XXX this check is probably pointless in the CCF context */
507
- if (dd -> last_rounded_rate != rate ) {
508
- rrate = __clk_round_rate (hw -> clk , rate );
509
- if (rrate != rate ) {
510
- pr_warn ("%s: %s: final rate %lu does not match desired rate %lu\n" ,
511
- __func__ , __clk_get_name (hw -> clk ),
512
- rrate , rate );
513
- rate = rrate ;
514
- }
515
- }
520
+ else
521
+ ret = _omap3_noncore_dpll_lock (clk );
516
522
517
- if ( dd -> last_rounded_rate == 0 )
518
- return - EINVAL ;
523
+ return ret ;
524
+ }
519
525
520
- /* Freqsel is available only on OMAP343X devices */
521
- if (ti_clk_features .flags & TI_CLK_DPLL_HAS_FREQSEL ) {
522
- freqsel = _omap3_dpll_compute_freqsel (clk ,
523
- dd -> last_rounded_n );
524
- WARN_ON (!freqsel );
525
- }
526
+ /**
527
+ * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
528
+ * @hw: pointer to the clock to set parent for
529
+ * @rate: target rate for the clock
530
+ * @parent_rate: rate of the parent clock
531
+ *
532
+ * Sets rate for a DPLL clock. First checks if the clock parent is
533
+ * reference clock (in bypass mode, the rate of the clock can't be
534
+ * changed) and proceeds with the rate change operation. Returns 0
535
+ * with success, negative error value otherwise.
536
+ */
537
+ int omap3_noncore_dpll_set_rate (struct clk_hw * hw , unsigned long rate ,
538
+ unsigned long parent_rate )
539
+ {
540
+ struct clk_hw_omap * clk = to_clk_hw_omap (hw );
541
+ struct dpll_data * dd ;
542
+ u16 freqsel = 0 ;
543
+ int ret ;
544
+
545
+ if (!hw || !rate )
546
+ return - EINVAL ;
547
+
548
+ dd = clk -> dpll_data ;
549
+ if (!dd )
550
+ return - EINVAL ;
526
551
527
- pr_debug ("%s: %s: set rate: locking rate to %lu.\n" ,
528
- __func__ , __clk_get_name (hw -> clk ), rate );
552
+ if (__clk_get_parent (hw -> clk ) != dd -> clk_ref )
553
+ return - EINVAL ;
554
+
555
+ if (dd -> last_rounded_rate == 0 )
556
+ return - EINVAL ;
529
557
530
- ret = omap3_noncore_dpll_program (clk , freqsel );
531
- if (!ret )
532
- new_parent = dd -> clk_ref ;
533
- clk_disable (dd -> clk_ref );
534
- __clk_unprepare (dd -> clk_ref );
558
+ /* Freqsel is available only on OMAP343X devices */
559
+ if (ti_clk_features .flags & TI_CLK_DPLL_HAS_FREQSEL ) {
560
+ freqsel = _omap3_dpll_compute_freqsel (clk , dd -> last_rounded_n );
561
+ WARN_ON (!freqsel );
535
562
}
536
- /*
537
- * FIXME - this is all wrong. common code handles reparenting and
538
- * migrating prepare/enable counts. dplls should be a multiplexer
539
- * clock and this should be a set_parent operation so that all of that
540
- * stuff is inherited for free
541
- */
542
563
543
- if (! ret && clk_get_parent ( hw -> clk ) != new_parent )
544
- __clk_reparent (hw -> clk , new_parent );
564
+ pr_debug ( "%s: %s: set rate: locking rate to %lu.\n" , __func__ ,
565
+ __clk_get_name (hw -> clk ), rate );
545
566
546
- return 0 ;
567
+ ret = omap3_noncore_dpll_program (clk , freqsel );
568
+
569
+ return ret ;
570
+ }
571
+
572
+ /**
573
+ * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
574
+ * @hw: pointer to the clock to set rate and parent for
575
+ * @rate: target rate for the DPLL
576
+ * @parent_rate: clock rate of the DPLL parent
577
+ * @index: new parent index for the DPLL, 0 - reference, 1 - bypass
578
+ *
579
+ * Sets rate and parent for a DPLL clock. If new parent is the bypass
580
+ * clock, only selects the parent. Otherwise proceeds with a rate
581
+ * change, as this will effectively also change the parent as the
582
+ * DPLL is put into locked mode. Returns 0 with success, negative error
583
+ * value otherwise.
584
+ */
585
+ int omap3_noncore_dpll_set_rate_and_parent (struct clk_hw * hw ,
586
+ unsigned long rate ,
587
+ unsigned long parent_rate ,
588
+ u8 index )
589
+ {
590
+ int ret ;
591
+
592
+ if (!hw || !rate )
593
+ return - EINVAL ;
594
+
595
+ /*
596
+ * clk-ref at index[0], in which case we only need to set rate,
597
+ * the parent will be changed automatically with the lock sequence.
598
+ * With clk-bypass case we only need to change parent.
599
+ */
600
+ if (index )
601
+ ret = omap3_noncore_dpll_set_parent (hw , index );
602
+ else
603
+ ret = omap3_noncore_dpll_set_rate (hw , rate , parent_rate );
604
+
605
+ return ret ;
547
606
}
548
607
549
608
/* DPLL autoidle read/set code */
0 commit comments