These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / msm / dsi / pll / dsi_pll.c
1 /*
2  * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include "dsi_pll.h"
15
16 static int dsi_pll_enable(struct msm_dsi_pll *pll)
17 {
18         int i, ret = 0;
19
20         /*
21          * Certain PLLs do not allow VCO rate update when it is on.
22          * Keep track of their status to turn on/off after set rate success.
23          */
24         if (unlikely(pll->pll_on))
25                 return 0;
26
27         /* Try all enable sequences until one succeeds */
28         for (i = 0; i < pll->en_seq_cnt; i++) {
29                 ret = pll->enable_seqs[i](pll);
30                 DBG("DSI PLL %s after sequence #%d",
31                         ret ? "unlocked" : "locked", i + 1);
32                 if (!ret)
33                         break;
34         }
35
36         if (ret) {
37                 DRM_ERROR("DSI PLL failed to lock\n");
38                 return ret;
39         }
40
41         pll->pll_on = true;
42
43         return 0;
44 }
45
46 static void dsi_pll_disable(struct msm_dsi_pll *pll)
47 {
48         if (unlikely(!pll->pll_on))
49                 return;
50
51         pll->disable_seq(pll);
52
53         pll->pll_on = false;
54 }
55
56 /*
57  * DSI PLL Helper functions
58  */
59 long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw,
60                 unsigned long rate, unsigned long *parent_rate)
61 {
62         struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
63
64         if      (rate < pll->min_rate)
65                 return  pll->min_rate;
66         else if (rate > pll->max_rate)
67                 return  pll->max_rate;
68         else
69                 return rate;
70 }
71
72 int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw)
73 {
74         struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
75
76         return dsi_pll_enable(pll);
77 }
78
79 void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw)
80 {
81         struct msm_dsi_pll *pll = hw_clk_to_pll(hw);
82
83         dsi_pll_disable(pll);
84 }
85
86 void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev,
87                                         struct clk **clks, u32 num_clks)
88 {
89         of_clk_del_provider(pdev->dev.of_node);
90
91         if (!num_clks || !clks)
92                 return;
93
94         do {
95                 clk_unregister(clks[--num_clks]);
96                 clks[num_clks] = NULL;
97         } while (num_clks);
98 }
99
100 /*
101  * DSI PLL API
102  */
103 int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll,
104         struct clk **byte_clk_provider, struct clk **pixel_clk_provider)
105 {
106         if (pll->get_provider)
107                 return pll->get_provider(pll,
108                                         byte_clk_provider,
109                                         pixel_clk_provider);
110
111         return -EINVAL;
112 }
113
114 void msm_dsi_pll_destroy(struct msm_dsi_pll *pll)
115 {
116         if (pll->destroy)
117                 pll->destroy(pll);
118 }
119
120 void msm_dsi_pll_save_state(struct msm_dsi_pll *pll)
121 {
122         if (pll->save_state) {
123                 pll->save_state(pll);
124                 pll->state_saved = true;
125         }
126 }
127
128 int msm_dsi_pll_restore_state(struct msm_dsi_pll *pll)
129 {
130         int ret;
131
132         if (pll->restore_state && pll->state_saved) {
133                 ret = pll->restore_state(pll);
134                 if (ret)
135                         return ret;
136
137                 pll->state_saved = false;
138         }
139
140         return 0;
141 }
142
143 struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
144                         enum msm_dsi_phy_type type, int id)
145 {
146         struct device *dev = &pdev->dev;
147         struct msm_dsi_pll *pll;
148
149         switch (type) {
150         case MSM_DSI_PHY_28NM_HPM:
151         case MSM_DSI_PHY_28NM_LP:
152                 pll = msm_dsi_pll_28nm_init(pdev, type, id);
153                 break;
154         default:
155                 pll = ERR_PTR(-ENXIO);
156                 break;
157         }
158
159         if (IS_ERR(pll)) {
160                 dev_err(dev, "%s: failed to init DSI PLL\n", __func__);
161                 return NULL;
162         }
163
164         pll->type = type;
165
166         DBG("DSI:%d PLL registered", id);
167
168         return pll;
169 }
170