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