GNU Linux-libre 4.9.328-gnu1
[releases.git] / drivers / gpu / drm / msm / hdmi / hdmi_pll_8960.c
1 /*
2  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
3  * Copyright (C) 2013 Red Hat
4  * Author: Rob Clark <robdclark@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/clk-provider.h>
20 #include "hdmi.h"
21
22 struct hdmi_pll_8960 {
23         struct platform_device *pdev;
24         struct clk_hw clk_hw;
25         void __iomem *mmio;
26
27         unsigned long pixclk;
28 };
29
30 #define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw)
31
32 /*
33  * HDMI PLL:
34  *
35  * To get the parent clock setup properly, we need to plug in hdmi pll
36  * configuration into common-clock-framework.
37  */
38
39 struct pll_rate {
40         unsigned long rate;
41         int num_reg;
42         struct {
43                 u32 val;
44                 u32 reg;
45         } conf[32];
46 };
47
48 /* NOTE: keep sorted highest freq to lowest: */
49 static const struct pll_rate freqtbl[] = {
50         { 154000000, 14, {
51                 { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
52                 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
53                 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
54                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
55                 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
56                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
57                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
58                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
59                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
60                 { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
61                 { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
62                 { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
63                 { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
64                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
65                         }
66         },
67         /* 1080p60/1080p50 case */
68         { 148500000, 27, {
69                 { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
70                 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
71                 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
72                 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
73                 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG  },
74                 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
75                 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B       },
76                 { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
77                 { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
78                 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
79                 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
80                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
81                 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0      },
82                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1      },
83                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2      },
84                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3      },
85                 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0  },
86                 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1  },
87                 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2  },
88                 { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
89                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
90                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
91                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
92                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
93                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
94                 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6   },
95                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7   },
96                         }
97         },
98         { 108000000, 13, {
99                 { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
100                 { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
101                 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
102                 { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
103                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
104                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
105                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
106                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
107                 { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
108                 { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
109                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
110                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
111                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
112                         }
113         },
114         /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
115         { 74250000, 8, {
116                 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B       },
117                 { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
118                 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
119                 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
120                 { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
121                 { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
122                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
123                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
124                         }
125         },
126         { 74176000, 14, {
127                 { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
128                 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
129                 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
130                 { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
131                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
132                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
133                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
134                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
135                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
136                 { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
137                 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
138                 { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
139                 { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
140                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
141                         }
142         },
143         { 65000000, 14, {
144                 { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
145                 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
146                 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
147                 { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
148                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
149                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
150                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
151                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
152                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
153                 { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
154                 { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
155                 { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
156                 { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
157                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
158                         }
159         },
160         /* 480p60/480i60 */
161         { 27030000, 18, {
162                 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B       },
163                 { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
164                 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
165                 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
166                 { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
167                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
168                 { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
169                 { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
170                 { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
171                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
172                 { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
173                 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
174                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
175                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
176                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
177                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
178                 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6   },
179                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7   },
180                         }
181         },
182         /* 576p50/576i50 */
183         { 27000000, 27, {
184                 { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
185                 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
186                 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
187                 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
188                 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG  },
189                 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
190                 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B       },
191                 { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
192                 { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
193                 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
194                 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
195                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
196                 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0      },
197                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1      },
198                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2      },
199                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3      },
200                 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0  },
201                 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1  },
202                 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2  },
203                 { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
204                 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
205                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
206                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
207                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
208                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
209                 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6   },
210                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7   },
211                         }
212         },
213         /* 640x480p60 */
214         { 25200000, 27, {
215                 { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG    },
216                 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
217                 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
218                 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
219                 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG  },
220                 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
221                 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B       },
222                 { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0      },
223                 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1      },
224                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2      },
225                 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3      },
226                 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4      },
227                 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0      },
228                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1      },
229                 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2      },
230                 { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3      },
231                 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0  },
232                 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1  },
233                 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2  },
234                 { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0   },
235                 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1   },
236                 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2   },
237                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3   },
238                 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4   },
239                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5   },
240                 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6   },
241                 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7   },
242                         }
243         },
244 };
245
246 static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data)
247 {
248         msm_writel(data, pll->mmio + reg);
249 }
250
251 static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg)
252 {
253         return msm_readl(pll->mmio + reg);
254 }
255
256 static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll)
257 {
258         return platform_get_drvdata(pll->pdev);
259 }
260
261 static int hdmi_pll_enable(struct clk_hw *hw)
262 {
263         struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
264         struct hdmi_phy *phy = pll_get_phy(pll);
265         int timeout_count, pll_lock_retry = 10;
266         unsigned int val;
267
268         DBG("");
269
270         /* Assert PLL S/W reset */
271         pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
272         pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
273         pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
274
275         /* Wait for a short time before de-asserting
276          * to allow the hardware to complete its job.
277          * This much of delay should be fine for hardware
278          * to assert and de-assert.
279          */
280         udelay(10);
281
282         /* De-assert PLL S/W reset */
283         pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
284
285         val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
286         val |= HDMI_8960_PHY_REG12_SW_RESET;
287         /* Assert PHY S/W reset */
288         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
289         val &= ~HDMI_8960_PHY_REG12_SW_RESET;
290         /*
291          * Wait for a short time before de-asserting to allow the hardware to
292          * complete its job. This much of delay should be fine for hardware to
293          * assert and de-assert.
294          */
295         udelay(10);
296         /* De-assert PHY S/W reset */
297         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
298         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2,  0x3f);
299
300         val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
301         val |= HDMI_8960_PHY_REG12_PWRDN_B;
302         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
303         /* Wait 10 us for enabling global power for PHY */
304         mb();
305         udelay(10);
306
307         val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
308         val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
309         val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
310         pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
311         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80);
312
313         timeout_count = 1000;
314         while (--pll_lock_retry > 0) {
315                 /* are we there yet? */
316                 val = pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0);
317                 if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
318                         break;
319
320                 udelay(1);
321
322                 if (--timeout_count > 0)
323                         continue;
324
325                 /*
326                  * PLL has still not locked.
327                  * Do a software reset and try again
328                  * Assert PLL S/W reset first
329                  */
330                 pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
331                 udelay(10);
332                 pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
333
334                 /*
335                  * Wait for a short duration for the PLL calibration
336                  * before checking if the PLL gets locked
337                  */
338                 udelay(350);
339
340                 timeout_count = 1000;
341         }
342
343         return 0;
344 }
345
346 static void hdmi_pll_disable(struct clk_hw *hw)
347 {
348         struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
349         struct hdmi_phy *phy = pll_get_phy(pll);
350         unsigned int val;
351
352         DBG("");
353
354         val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
355         val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
356         hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
357
358         val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
359         val |= HDMI_8960_PHY_REG12_SW_RESET;
360         val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
361         pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
362         /* Make sure HDMI PHY/PLL are powered down */
363         mb();
364 }
365
366 static const struct pll_rate *find_rate(unsigned long rate)
367 {
368         int i;
369
370         for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
371                 if (rate > freqtbl[i].rate)
372                         return &freqtbl[i - 1];
373
374         return &freqtbl[i - 1];
375 }
376
377 static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
378                                           unsigned long parent_rate)
379 {
380         struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
381
382         return pll->pixclk;
383 }
384
385 static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
386                                 unsigned long *parent_rate)
387 {
388         const struct pll_rate *pll_rate = find_rate(rate);
389
390         return pll_rate->rate;
391 }
392
393 static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
394                              unsigned long parent_rate)
395 {
396         struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
397         const struct pll_rate *pll_rate = find_rate(rate);
398         int i;
399
400         DBG("rate=%lu", rate);
401
402         for (i = 0; i < pll_rate->num_reg; i++)
403                 pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val);
404
405         pll->pixclk = rate;
406
407         return 0;
408 }
409
410 static const struct clk_ops hdmi_pll_ops = {
411         .enable = hdmi_pll_enable,
412         .disable = hdmi_pll_disable,
413         .recalc_rate = hdmi_pll_recalc_rate,
414         .round_rate = hdmi_pll_round_rate,
415         .set_rate = hdmi_pll_set_rate,
416 };
417
418 static const char * const hdmi_pll_parents[] = {
419         "pxo",
420 };
421
422 static struct clk_init_data pll_init = {
423         .name = "hdmi_pll",
424         .ops = &hdmi_pll_ops,
425         .parent_names = hdmi_pll_parents,
426         .num_parents = ARRAY_SIZE(hdmi_pll_parents),
427         .flags = CLK_IGNORE_UNUSED,
428 };
429
430 int msm_hdmi_pll_8960_init(struct platform_device *pdev)
431 {
432         struct device *dev = &pdev->dev;
433         struct hdmi_pll_8960 *pll;
434         struct clk *clk;
435         int i;
436
437         /* sanity check: */
438         for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
439                 if (WARN_ON(freqtbl[i].rate < freqtbl[i + 1].rate))
440                         return -EINVAL;
441
442         pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
443         if (!pll)
444                 return -ENOMEM;
445
446         pll->mmio = msm_ioremap(pdev, "hdmi_pll", "HDMI_PLL");
447         if (IS_ERR(pll->mmio)) {
448                 dev_err(dev, "failed to map pll base\n");
449                 return -ENOMEM;
450         }
451
452         pll->pdev = pdev;
453         pll->clk_hw.init = &pll_init;
454
455         clk = devm_clk_register(dev, &pll->clk_hw);
456         if (IS_ERR(clk)) {
457                 dev_err(dev, "failed to register pll clock\n");
458                 return -EINVAL;
459         }
460
461         return 0;
462 }