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