1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * MMP Audio Clock Controller driver 4 * 5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk> 6 */ 7 8 #include <linux/clk-provider.h> 9 #include <linux/io.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/pm_clock.h> 13 #include <linux/pm_runtime.h> 14 #include <linux/slab.h> 15 #include <dt-bindings/clock/marvell,mmp2-audio.h> 16 17 /* Audio Controller Registers */ 18 #define SSPA_AUD_CTRL 0x04 19 #define SSPA_AUD_PLL_CTRL0 0x08 20 #define SSPA_AUD_PLL_CTRL1 0x0c 21 22 /* SSPA Audio Control Register */ 23 #define SSPA_AUD_CTRL_SYSCLK_SHIFT 0 24 #define SSPA_AUD_CTRL_SYSCLK_DIV_SHIFT 1 25 #define SSPA_AUD_CTRL_SSPA0_MUX_SHIFT 7 26 #define SSPA_AUD_CTRL_SSPA0_SHIFT 8 27 #define SSPA_AUD_CTRL_SSPA0_DIV_SHIFT 9 28 #define SSPA_AUD_CTRL_SSPA1_SHIFT 16 29 #define SSPA_AUD_CTRL_SSPA1_DIV_SHIFT 17 30 #define SSPA_AUD_CTRL_SSPA1_MUX_SHIFT 23 31 #define SSPA_AUD_CTRL_DIV_MASK 0x7e 32 33 /* SSPA Audio PLL Control 0 Register */ 34 #define SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO_MASK (0x7 << 28) 35 #define SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(x) ((x) << 28) 36 #define SSPA_AUD_PLL_CTRL0_FRACT_MASK (0xfffff << 8) 37 #define SSPA_AUD_PLL_CTRL0_FRACT(x) ((x) << 8) 38 #define SSPA_AUD_PLL_CTRL0_ENA_DITHER (1 << 7) 39 #define SSPA_AUD_PLL_CTRL0_ICP_2UA (0 << 5) 40 #define SSPA_AUD_PLL_CTRL0_ICP_5UA (1 << 5) 41 #define SSPA_AUD_PLL_CTRL0_ICP_7UA (2 << 5) 42 #define SSPA_AUD_PLL_CTRL0_ICP_10UA (3 << 5) 43 #define SSPA_AUD_PLL_CTRL0_DIV_FBCCLK_MASK (0x3 << 3) 44 #define SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(x) ((x) << 3) 45 #define SSPA_AUD_PLL_CTRL0_DIV_MCLK_MASK (0x1 << 2) 46 #define SSPA_AUD_PLL_CTRL0_DIV_MCLK(x) ((x) << 2) 47 #define SSPA_AUD_PLL_CTRL0_PD_OVPROT_DIS (1 << 1) 48 #define SSPA_AUD_PLL_CTRL0_PU (1 << 0) 49 50 /* SSPA Audio PLL Control 1 Register */ 51 #define SSPA_AUD_PLL_CTRL1_SEL_FAST_CLK (1 << 24) 52 #define SSPA_AUD_PLL_CTRL1_CLK_SEL_MASK (1 << 11) 53 #define SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL (1 << 11) 54 #define SSPA_AUD_PLL_CTRL1_CLK_SEL_VCXO (0 << 11) 55 #define SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN_MASK (0x7ff << 0) 56 #define SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(x) ((x) << 0) 57 58 #define CLK_AUDIO_NR_CLKS 3 59 60 struct mmp2_audio_clk { 61 void __iomem *mmio_base; 62 63 struct clk_hw audio_pll_hw; 64 struct clk_mux sspa_mux; 65 struct clk_mux sspa1_mux; 66 struct clk_divider sysclk_div; 67 struct clk_divider sspa0_div; 68 struct clk_divider sspa1_div; 69 struct clk_gate sysclk_gate; 70 struct clk_gate sspa0_gate; 71 struct clk_gate sspa1_gate; 72 73 u32 aud_ctrl; 74 u32 aud_pll_ctrl0; 75 u32 aud_pll_ctrl1; 76 77 spinlock_t lock; 78 79 /* Must be last */ 80 struct clk_hw_onecell_data clk_data; 81 }; 82 83 static const struct { 84 unsigned long parent_rate; 85 unsigned long freq_vco; 86 unsigned char mclk; 87 unsigned char fbcclk; 88 unsigned short fract; 89 } predivs[] = { 90 { 26000000, 135475200, 0, 0, 0x8a18 }, 91 { 26000000, 147456000, 0, 1, 0x0da1 }, 92 { 38400000, 135475200, 1, 2, 0x8208 }, 93 { 38400000, 147456000, 1, 3, 0xaaaa }, 94 }; 95 96 static const struct { 97 unsigned char divisor; 98 unsigned char modulo; 99 unsigned char pattern; 100 } postdivs[] = { 101 { 1, 3, 0, }, 102 { 2, 5, 0, }, 103 { 4, 0, 0, }, 104 { 6, 1, 1, }, 105 { 8, 1, 0, }, 106 { 9, 1, 2, }, 107 { 12, 2, 1, }, 108 { 16, 2, 0, }, 109 { 18, 2, 2, }, 110 { 24, 4, 1, }, 111 { 36, 4, 2, }, 112 { 48, 6, 1, }, 113 { 72, 6, 2, }, 114 }; 115 116 static unsigned long audio_pll_recalc_rate(struct clk_hw *hw, 117 unsigned long parent_rate) 118 { 119 struct mmp2_audio_clk *priv = container_of(hw, struct mmp2_audio_clk, audio_pll_hw); 120 unsigned int prediv; 121 unsigned int postdiv; 122 u32 aud_pll_ctrl0; 123 u32 aud_pll_ctrl1; 124 125 aud_pll_ctrl0 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL0); 126 aud_pll_ctrl0 &= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO_MASK | 127 SSPA_AUD_PLL_CTRL0_FRACT_MASK | 128 SSPA_AUD_PLL_CTRL0_ENA_DITHER | 129 SSPA_AUD_PLL_CTRL0_DIV_FBCCLK_MASK | 130 SSPA_AUD_PLL_CTRL0_DIV_MCLK_MASK | 131 SSPA_AUD_PLL_CTRL0_PU; 132 133 aud_pll_ctrl1 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL1); 134 aud_pll_ctrl1 &= SSPA_AUD_PLL_CTRL1_CLK_SEL_MASK | 135 SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN_MASK; 136 137 for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) { 138 if (predivs[prediv].parent_rate != parent_rate) 139 continue; 140 for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) { 141 unsigned long freq; 142 u32 val; 143 144 val = SSPA_AUD_PLL_CTRL0_ENA_DITHER; 145 val |= SSPA_AUD_PLL_CTRL0_PU; 146 val |= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(postdivs[postdiv].modulo); 147 val |= SSPA_AUD_PLL_CTRL0_FRACT(predivs[prediv].fract); 148 val |= SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(predivs[prediv].fbcclk); 149 val |= SSPA_AUD_PLL_CTRL0_DIV_MCLK(predivs[prediv].mclk); 150 if (val != aud_pll_ctrl0) 151 continue; 152 153 val = SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL; 154 val |= SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(postdivs[postdiv].pattern); 155 if (val != aud_pll_ctrl1) 156 continue; 157 158 freq = predivs[prediv].freq_vco; 159 freq /= postdivs[postdiv].divisor; 160 return freq; 161 } 162 } 163 164 return 0; 165 } 166 167 static long audio_pll_round_rate(struct clk_hw *hw, unsigned long rate, 168 unsigned long *parent_rate) 169 { 170 unsigned int prediv; 171 unsigned int postdiv; 172 long rounded = 0; 173 174 for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) { 175 if (predivs[prediv].parent_rate != *parent_rate) 176 continue; 177 for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) { 178 long freq = predivs[prediv].freq_vco; 179 180 freq /= postdivs[postdiv].divisor; 181 if (freq == rate) 182 return rate; 183 if (freq < rate) 184 continue; 185 if (rounded && freq > rounded) 186 continue; 187 rounded = freq; 188 } 189 } 190 191 return rounded; 192 } 193 194 static int audio_pll_set_rate(struct clk_hw *hw, unsigned long rate, 195 unsigned long parent_rate) 196 { 197 struct mmp2_audio_clk *priv = container_of(hw, struct mmp2_audio_clk, audio_pll_hw); 198 unsigned int prediv; 199 unsigned int postdiv; 200 unsigned long val; 201 202 for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) { 203 if (predivs[prediv].parent_rate != parent_rate) 204 continue; 205 206 for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) { 207 if (rate * postdivs[postdiv].divisor != predivs[prediv].freq_vco) 208 continue; 209 210 val = SSPA_AUD_PLL_CTRL0_ENA_DITHER; 211 val |= SSPA_AUD_PLL_CTRL0_PU; 212 val |= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(postdivs[postdiv].modulo); 213 val |= SSPA_AUD_PLL_CTRL0_FRACT(predivs[prediv].fract); 214 val |= SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(predivs[prediv].fbcclk); 215 val |= SSPA_AUD_PLL_CTRL0_DIV_MCLK(predivs[prediv].mclk); 216 writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL0); 217 218 val = SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL; 219 val |= SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(postdivs[postdiv].pattern); 220 writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL1); 221 222 return 0; 223 } 224 } 225 226 return -ERANGE; 227 } 228 229 static const struct clk_ops audio_pll_ops = { 230 .recalc_rate = audio_pll_recalc_rate, 231 .round_rate = audio_pll_round_rate, 232 .set_rate = audio_pll_set_rate, 233 }; 234 235 static int register_clocks(struct mmp2_audio_clk *priv, struct device *dev) 236 { 237 const struct clk_parent_data sspa_mux_parents[] = { 238 { .hw = &priv->audio_pll_hw }, 239 { .fw_name = "i2s0" }, 240 }; 241 const struct clk_parent_data sspa1_mux_parents[] = { 242 { .hw = &priv->audio_pll_hw }, 243 { .fw_name = "i2s1" }, 244 }; 245 int ret; 246 247 priv->audio_pll_hw.init = CLK_HW_INIT_FW_NAME("audio_pll", 248 "vctcxo", &audio_pll_ops, 249 CLK_SET_RATE_PARENT); 250 ret = devm_clk_hw_register(dev, &priv->audio_pll_hw); 251 if (ret) 252 return ret; 253 254 priv->sspa_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa_mux", 255 sspa_mux_parents, &clk_mux_ops, 256 CLK_SET_RATE_PARENT); 257 priv->sspa_mux.reg = priv->mmio_base + SSPA_AUD_CTRL; 258 priv->sspa_mux.mask = 1; 259 priv->sspa_mux.shift = SSPA_AUD_CTRL_SSPA0_MUX_SHIFT; 260 ret = devm_clk_hw_register(dev, &priv->sspa_mux.hw); 261 if (ret) 262 return ret; 263 264 priv->sysclk_div.hw.init = CLK_HW_INIT_HW("sys_div", 265 &priv->sspa_mux.hw, &clk_divider_ops, 266 CLK_SET_RATE_PARENT); 267 priv->sysclk_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 268 priv->sysclk_div.shift = SSPA_AUD_CTRL_SYSCLK_DIV_SHIFT; 269 priv->sysclk_div.width = 6; 270 priv->sysclk_div.flags = CLK_DIVIDER_ONE_BASED; 271 priv->sysclk_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 272 priv->sysclk_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 273 ret = devm_clk_hw_register(dev, &priv->sysclk_div.hw); 274 if (ret) 275 return ret; 276 277 priv->sysclk_gate.hw.init = CLK_HW_INIT_HW("sys_clk", 278 &priv->sysclk_div.hw, &clk_gate_ops, 279 CLK_SET_RATE_PARENT); 280 priv->sysclk_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 281 priv->sysclk_gate.bit_idx = SSPA_AUD_CTRL_SYSCLK_SHIFT; 282 ret = devm_clk_hw_register(dev, &priv->sysclk_gate.hw); 283 if (ret) 284 return ret; 285 286 priv->sspa0_div.hw.init = CLK_HW_INIT_HW("sspa0_div", 287 &priv->sspa_mux.hw, &clk_divider_ops, 0); 288 priv->sspa0_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 289 priv->sspa0_div.shift = SSPA_AUD_CTRL_SSPA0_DIV_SHIFT; 290 priv->sspa0_div.width = 6; 291 priv->sspa0_div.flags = CLK_DIVIDER_ONE_BASED; 292 priv->sspa0_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 293 priv->sspa0_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 294 ret = devm_clk_hw_register(dev, &priv->sspa0_div.hw); 295 if (ret) 296 return ret; 297 298 priv->sspa0_gate.hw.init = CLK_HW_INIT_HW("sspa0_clk", 299 &priv->sspa0_div.hw, &clk_gate_ops, 300 CLK_SET_RATE_PARENT); 301 priv->sspa0_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 302 priv->sspa0_gate.bit_idx = SSPA_AUD_CTRL_SSPA0_SHIFT; 303 ret = devm_clk_hw_register(dev, &priv->sspa0_gate.hw); 304 if (ret) 305 return ret; 306 307 priv->sspa1_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa1_mux", 308 sspa1_mux_parents, &clk_mux_ops, 309 CLK_SET_RATE_PARENT); 310 priv->sspa1_mux.reg = priv->mmio_base + SSPA_AUD_CTRL; 311 priv->sspa1_mux.mask = 1; 312 priv->sspa1_mux.shift = SSPA_AUD_CTRL_SSPA1_MUX_SHIFT; 313 ret = devm_clk_hw_register(dev, &priv->sspa1_mux.hw); 314 if (ret) 315 return ret; 316 317 priv->sspa1_div.hw.init = CLK_HW_INIT_HW("sspa1_div", 318 &priv->sspa1_mux.hw, &clk_divider_ops, 0); 319 priv->sspa1_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 320 priv->sspa1_div.shift = SSPA_AUD_CTRL_SSPA1_DIV_SHIFT; 321 priv->sspa1_div.width = 6; 322 priv->sspa1_div.flags = CLK_DIVIDER_ONE_BASED; 323 priv->sspa1_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 324 priv->sspa1_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 325 ret = devm_clk_hw_register(dev, &priv->sspa1_div.hw); 326 if (ret) 327 return ret; 328 329 priv->sspa1_gate.hw.init = CLK_HW_INIT_HW("sspa1_clk", 330 &priv->sspa1_div.hw, &clk_gate_ops, 331 CLK_SET_RATE_PARENT); 332 priv->sspa1_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 333 priv->sspa1_gate.bit_idx = SSPA_AUD_CTRL_SSPA1_SHIFT; 334 ret = devm_clk_hw_register(dev, &priv->sspa1_gate.hw); 335 if (ret) 336 return ret; 337 338 priv->clk_data.hws[MMP2_CLK_AUDIO_SYSCLK] = &priv->sysclk_gate.hw; 339 priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA0] = &priv->sspa0_gate.hw; 340 priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA1] = &priv->sspa1_gate.hw; 341 priv->clk_data.num = CLK_AUDIO_NR_CLKS; 342 343 return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, 344 &priv->clk_data); 345 } 346 347 static int mmp2_audio_clk_probe(struct platform_device *pdev) 348 { 349 struct mmp2_audio_clk *priv; 350 int ret; 351 352 priv = devm_kzalloc(&pdev->dev, 353 struct_size(priv, clk_data.hws, 354 CLK_AUDIO_NR_CLKS), 355 GFP_KERNEL); 356 if (!priv) 357 return -ENOMEM; 358 359 spin_lock_init(&priv->lock); 360 platform_set_drvdata(pdev, priv); 361 362 priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); 363 if (IS_ERR(priv->mmio_base)) 364 return PTR_ERR(priv->mmio_base); 365 366 pm_runtime_enable(&pdev->dev); 367 ret = pm_clk_create(&pdev->dev); 368 if (ret) 369 goto disable_pm_runtime; 370 371 ret = pm_clk_add(&pdev->dev, "audio"); 372 if (ret) 373 goto destroy_pm_clk; 374 375 ret = register_clocks(priv, &pdev->dev); 376 if (ret) 377 goto destroy_pm_clk; 378 379 return 0; 380 381 destroy_pm_clk: 382 pm_clk_destroy(&pdev->dev); 383 disable_pm_runtime: 384 pm_runtime_disable(&pdev->dev); 385 386 return ret; 387 } 388 389 static void mmp2_audio_clk_remove(struct platform_device *pdev) 390 { 391 pm_clk_destroy(&pdev->dev); 392 pm_runtime_disable(&pdev->dev); 393 } 394 395 #ifdef CONFIG_PM 396 static int mmp2_audio_clk_suspend(struct device *dev) 397 { 398 struct mmp2_audio_clk *priv = dev_get_drvdata(dev); 399 400 priv->aud_ctrl = readl(priv->mmio_base + SSPA_AUD_CTRL); 401 priv->aud_pll_ctrl0 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL0); 402 priv->aud_pll_ctrl1 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL1); 403 pm_clk_suspend(dev); 404 405 return 0; 406 } 407 408 static int mmp2_audio_clk_resume(struct device *dev) 409 { 410 struct mmp2_audio_clk *priv = dev_get_drvdata(dev); 411 412 pm_clk_resume(dev); 413 writel(priv->aud_ctrl, priv->mmio_base + SSPA_AUD_CTRL); 414 writel(priv->aud_pll_ctrl0, priv->mmio_base + SSPA_AUD_PLL_CTRL0); 415 writel(priv->aud_pll_ctrl1, priv->mmio_base + SSPA_AUD_PLL_CTRL1); 416 417 return 0; 418 } 419 #endif 420 421 static const struct dev_pm_ops mmp2_audio_clk_pm_ops = { 422 SET_RUNTIME_PM_OPS(mmp2_audio_clk_suspend, mmp2_audio_clk_resume, NULL) 423 }; 424 425 static const struct of_device_id mmp2_audio_clk_of_match[] = { 426 { .compatible = "marvell,mmp2-audio-clock" }, 427 {} 428 }; 429 430 MODULE_DEVICE_TABLE(of, mmp2_audio_clk_of_match); 431 432 static struct platform_driver mmp2_audio_clk_driver = { 433 .driver = { 434 .name = "mmp2-audio-clock", 435 .of_match_table = of_match_ptr(mmp2_audio_clk_of_match), 436 .pm = &mmp2_audio_clk_pm_ops, 437 }, 438 .probe = mmp2_audio_clk_probe, 439 .remove = mmp2_audio_clk_remove, 440 }; 441 module_platform_driver(mmp2_audio_clk_driver); 442 443 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 444 MODULE_DESCRIPTION("Clock driver for MMP2 Audio subsystem"); 445 MODULE_LICENSE("GPL"); 446