aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchit Taneja <architt@codeaurora.org>2015-10-14 08:54:44 -0400
committerStephen Boyd <sboyd@codeaurora.org>2015-10-16 18:08:40 -0400
commitd8aa2beed870f088d4433b7075303e58764f0587 (patch)
tree029462ca09e042e324933efc03ee646f71dd0fa0
parentb1a0eeb4f6bbfb63c356578eaf76003faa58f56b (diff)
clk: qcom: clk-rcg: Add customized clk_ops for DSI RCGs
DSI specific RCG clocks required customized clk_ops. There are a total of 4 RCGs per DSI block: DSI, BYTE, ESC and PIXEL. There are a total of 2 clocks coming from the DSI PLL, which serve as inputs to these RCGs. The BYTE and ESC RCGs are fed by one of the post dividers of DSI1 or DSI2 PLLs, and the DSI and PIXEL RCGs are fed by another divider of the PLL. In each of the 2 groups above, only one of the clocks sets its parent. These are BYTE RCG and DSI RCG for each of the groups respectively, as shown in the diagram below. The DSI and BYTE RCGs serve as bypass clocks. We create a new set of ops clk_rcg_bypass2_ops, which are like the regular bypass ops, but don't take in a freq table, since the DSI driver using these clocks is parent-able. The PIXEL RCG needs to derive the required pixel clock using dsixpll. It parses a m/n frac table to retrieve the correct clock. The ESC RCG doesn't have a frac M/N block, it can just apply a pre- divider. Its ops simply check if the required clock rate can be achieved by the pre-divider. +-------------------+ | |---dsixpllbyte---o---> To byte RCG | | | (sets parent rate) | | | | | | | DSI 1/2 PLL | | | | o---> To esc RCG | | (doesn't set parent rate) | | | |----dsixpll-----o---> To dsi RCG +-------------------+ | (sets parent rate) ( x = 1, 2 ) | | o---> To pixel rcg (doesn't set parent rate) Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/qcom/clk-rcg.c230
-rw-r--r--drivers/clk/qcom/clk-rcg.h3
2 files changed, 233 insertions, 0 deletions
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index bccedc4b5756..bfbb28f450c2 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -542,6 +542,200 @@ static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate,
542 return __clk_rcg_set_rate(rcg, rcg->freq_tbl); 542 return __clk_rcg_set_rate(rcg, rcg->freq_tbl);
543} 543}
544 544
545static int clk_rcg_bypass2_determine_rate(struct clk_hw *hw,
546 struct clk_rate_request *req)
547{
548 struct clk_hw *p;
549
550 p = req->best_parent_hw;
551 req->best_parent_rate = clk_hw_round_rate(p, req->rate);
552 req->rate = req->best_parent_rate;
553
554 return 0;
555}
556
557static int clk_rcg_bypass2_set_rate(struct clk_hw *hw, unsigned long rate,
558 unsigned long parent_rate)
559{
560 struct clk_rcg *rcg = to_clk_rcg(hw);
561 struct freq_tbl f = { 0 };
562 u32 ns, src;
563 int i, ret, num_parents = clk_hw_get_num_parents(hw);
564
565 ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
566 if (ret)
567 return ret;
568
569 src = ns_to_src(&rcg->s, ns);
570 f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;
571
572 for (i = 0; i < num_parents; i++) {
573 if (src == rcg->s.parent_map[i].cfg) {
574 f.src = rcg->s.parent_map[i].src;
575 return __clk_rcg_set_rate(rcg, &f);
576 }
577 }
578
579 return -EINVAL;
580}
581
582static int clk_rcg_bypass2_set_rate_and_parent(struct clk_hw *hw,
583 unsigned long rate, unsigned long parent_rate, u8 index)
584{
585 /* Read the hardware to determine parent during set_rate */
586 return clk_rcg_bypass2_set_rate(hw, rate, parent_rate);
587}
588
589struct frac_entry {
590 int num;
591 int den;
592};
593
594static const struct frac_entry pixel_table[] = {
595 { 1, 2 },
596 { 1, 3 },
597 { 3, 16 },
598 { }
599};
600
601static int clk_rcg_pixel_determine_rate(struct clk_hw *hw,
602 struct clk_rate_request *req)
603{
604 int delta = 100000;
605 const struct frac_entry *frac = pixel_table;
606 unsigned long request, src_rate;
607
608 for (; frac->num; frac++) {
609 request = (req->rate * frac->den) / frac->num;
610
611 src_rate = clk_hw_round_rate(req->best_parent_hw, request);
612
613 if ((src_rate < (request - delta)) ||
614 (src_rate > (request + delta)))
615 continue;
616
617 req->best_parent_rate = src_rate;
618 req->rate = (src_rate * frac->num) / frac->den;
619 return 0;
620 }
621
622 return -EINVAL;
623}
624
625static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
626 unsigned long parent_rate)
627{
628 struct clk_rcg *rcg = to_clk_rcg(hw);
629 int delta = 100000;
630 const struct frac_entry *frac = pixel_table;
631 unsigned long request;
632 struct freq_tbl f = { 0 };
633 u32 ns, src;
634 int i, ret, num_parents = clk_hw_get_num_parents(hw);
635
636 ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
637 if (ret)
638 return ret;
639
640 src = ns_to_src(&rcg->s, ns);
641 f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1;
642
643 for (i = 0; i < num_parents; i++) {
644 if (src == rcg->s.parent_map[i].cfg) {
645 f.src = rcg->s.parent_map[i].src;
646 break;
647 }
648 }
649
650 /* let us find appropriate m/n values for this */
651 for (; frac->num; frac++) {
652 request = (rate * frac->den) / frac->num;
653
654 if ((parent_rate < (request - delta)) ||
655 (parent_rate > (request + delta)))
656 continue;
657
658 f.m = frac->num;
659 f.n = frac->den;
660
661 return __clk_rcg_set_rate(rcg, &f);
662 }
663
664 return -EINVAL;
665}
666
667static int clk_rcg_pixel_set_rate_and_parent(struct clk_hw *hw,
668 unsigned long rate, unsigned long parent_rate, u8 index)
669{
670 return clk_rcg_pixel_set_rate(hw, rate, parent_rate);
671}
672
673static int clk_rcg_esc_determine_rate(struct clk_hw *hw,
674 struct clk_rate_request *req)
675{
676 struct clk_rcg *rcg = to_clk_rcg(hw);
677 int pre_div_max = BIT(rcg->p.pre_div_width);
678 int div;
679 unsigned long src_rate;
680
681 if (req->rate == 0)
682 return -EINVAL;
683
684 src_rate = clk_hw_get_rate(req->best_parent_hw);
685
686 div = src_rate / req->rate;
687
688 if (div >= 1 && div <= pre_div_max) {
689 req->best_parent_rate = src_rate;
690 req->rate = src_rate / div;
691 return 0;
692 }
693
694 return -EINVAL;
695}
696
697static int clk_rcg_esc_set_rate(struct clk_hw *hw, unsigned long rate,
698 unsigned long parent_rate)
699{
700 struct clk_rcg *rcg = to_clk_rcg(hw);
701 struct freq_tbl f = { 0 };
702 int pre_div_max = BIT(rcg->p.pre_div_width);
703 int div;
704 u32 ns;
705 int i, ret, num_parents = clk_hw_get_num_parents(hw);
706
707 if (rate == 0)
708 return -EINVAL;
709
710 ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns);
711 if (ret)
712 return ret;
713
714 ns = ns_to_src(&rcg->s, ns);
715
716 for (i = 0; i < num_parents; i++) {
717 if (ns == rcg->s.parent_map[i].cfg) {
718 f.src = rcg->s.parent_map[i].src;
719 break;
720 }
721 }
722
723 div = parent_rate / rate;
724
725 if (div >= 1 && div <= pre_div_max) {
726 f.pre_div = div;
727 return __clk_rcg_set_rate(rcg, &f);
728 }
729
730 return -EINVAL;
731}
732
733static int clk_rcg_esc_set_rate_and_parent(struct clk_hw *hw,
734 unsigned long rate, unsigned long parent_rate, u8 index)
735{
736 return clk_rcg_esc_set_rate(hw, rate, parent_rate);
737}
738
545/* 739/*
546 * This type of clock has a glitch-free mux that switches between the output of 740 * This type of clock has a glitch-free mux that switches between the output of
547 * the M/N counter and an always on clock source (XO). When clk_set_rate() is 741 * the M/N counter and an always on clock source (XO). When clk_set_rate() is
@@ -639,6 +833,42 @@ const struct clk_ops clk_rcg_bypass_ops = {
639}; 833};
640EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops); 834EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops);
641 835
836const struct clk_ops clk_rcg_bypass2_ops = {
837 .enable = clk_enable_regmap,
838 .disable = clk_disable_regmap,
839 .get_parent = clk_rcg_get_parent,
840 .set_parent = clk_rcg_set_parent,
841 .recalc_rate = clk_rcg_recalc_rate,
842 .determine_rate = clk_rcg_bypass2_determine_rate,
843 .set_rate = clk_rcg_bypass2_set_rate,
844 .set_rate_and_parent = clk_rcg_bypass2_set_rate_and_parent,
845};
846EXPORT_SYMBOL_GPL(clk_rcg_bypass2_ops);
847
848const struct clk_ops clk_rcg_pixel_ops = {
849 .enable = clk_enable_regmap,
850 .disable = clk_disable_regmap,
851 .get_parent = clk_rcg_get_parent,
852 .set_parent = clk_rcg_set_parent,
853 .recalc_rate = clk_rcg_recalc_rate,
854 .determine_rate = clk_rcg_pixel_determine_rate,
855 .set_rate = clk_rcg_pixel_set_rate,
856 .set_rate_and_parent = clk_rcg_pixel_set_rate_and_parent,
857};
858EXPORT_SYMBOL_GPL(clk_rcg_pixel_ops);
859
860const struct clk_ops clk_rcg_esc_ops = {
861 .enable = clk_enable_regmap,
862 .disable = clk_disable_regmap,
863 .get_parent = clk_rcg_get_parent,
864 .set_parent = clk_rcg_set_parent,
865 .recalc_rate = clk_rcg_recalc_rate,
866 .determine_rate = clk_rcg_esc_determine_rate,
867 .set_rate = clk_rcg_esc_set_rate,
868 .set_rate_and_parent = clk_rcg_esc_set_rate_and_parent,
869};
870EXPORT_SYMBOL_GPL(clk_rcg_esc_ops);
871
642const struct clk_ops clk_rcg_lcc_ops = { 872const struct clk_ops clk_rcg_lcc_ops = {
643 .enable = clk_rcg_lcc_enable, 873 .enable = clk_rcg_lcc_enable,
644 .disable = clk_rcg_lcc_disable, 874 .disable = clk_rcg_lcc_disable,
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 5012e5b90cfb..4b1e94bdf29e 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -106,6 +106,9 @@ struct clk_rcg {
106 106
107extern const struct clk_ops clk_rcg_ops; 107extern const struct clk_ops clk_rcg_ops;
108extern const struct clk_ops clk_rcg_bypass_ops; 108extern const struct clk_ops clk_rcg_bypass_ops;
109extern const struct clk_ops clk_rcg_bypass2_ops;
110extern const struct clk_ops clk_rcg_pixel_ops;
111extern const struct clk_ops clk_rcg_esc_ops;
109extern const struct clk_ops clk_rcg_lcc_ops; 112extern const struct clk_ops clk_rcg_lcc_ops;
110 113
111#define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr) 114#define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr)