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 int audio_pll_determine_rate(struct clk_hw *hw, 168 struct clk_rate_request *req) 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 != req->best_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 == req->rate) 182 return 0; 183 if (freq < req->rate) 184 continue; 185 if (rounded && freq > rounded) 186 continue; 187 rounded = freq; 188 } 189 } 190 191 req->rate = rounded; 192 193 return 0; 194 } 195 196 static int audio_pll_set_rate(struct clk_hw *hw, unsigned long rate, 197 unsigned long parent_rate) 198 { 199 struct mmp2_audio_clk *priv = container_of(hw, struct mmp2_audio_clk, audio_pll_hw); 200 unsigned int prediv; 201 unsigned int postdiv; 202 unsigned long val; 203 204 for (prediv = 0; prediv < ARRAY_SIZE(predivs); prediv++) { 205 if (predivs[prediv].parent_rate != parent_rate) 206 continue; 207 208 for (postdiv = 0; postdiv < ARRAY_SIZE(postdivs); postdiv++) { 209 if (rate * postdivs[postdiv].divisor != predivs[prediv].freq_vco) 210 continue; 211 212 val = SSPA_AUD_PLL_CTRL0_ENA_DITHER; 213 val |= SSPA_AUD_PLL_CTRL0_PU; 214 val |= SSPA_AUD_PLL_CTRL0_DIV_OCLK_MODULO(postdivs[postdiv].modulo); 215 val |= SSPA_AUD_PLL_CTRL0_FRACT(predivs[prediv].fract); 216 val |= SSPA_AUD_PLL_CTRL0_DIV_FBCCLK(predivs[prediv].fbcclk); 217 val |= SSPA_AUD_PLL_CTRL0_DIV_MCLK(predivs[prediv].mclk); 218 writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL0); 219 220 val = SSPA_AUD_PLL_CTRL1_CLK_SEL_AUDIO_PLL; 221 val |= SSPA_AUD_PLL_CTRL1_DIV_OCLK_PATTERN(postdivs[postdiv].pattern); 222 writel(val, priv->mmio_base + SSPA_AUD_PLL_CTRL1); 223 224 return 0; 225 } 226 } 227 228 return -ERANGE; 229 } 230 231 static const struct clk_ops audio_pll_ops = { 232 .recalc_rate = audio_pll_recalc_rate, 233 .determine_rate = audio_pll_determine_rate, 234 .set_rate = audio_pll_set_rate, 235 }; 236 237 static int register_clocks(struct mmp2_audio_clk *priv, struct device *dev) 238 { 239 const struct clk_parent_data sspa_mux_parents[] = { 240 { .hw = &priv->audio_pll_hw }, 241 { .fw_name = "i2s0" }, 242 }; 243 const struct clk_parent_data sspa1_mux_parents[] = { 244 { .hw = &priv->audio_pll_hw }, 245 { .fw_name = "i2s1" }, 246 }; 247 int ret; 248 249 priv->audio_pll_hw.init = CLK_HW_INIT_FW_NAME("audio_pll", 250 "vctcxo", &audio_pll_ops, 251 CLK_SET_RATE_PARENT); 252 ret = devm_clk_hw_register(dev, &priv->audio_pll_hw); 253 if (ret) 254 return ret; 255 256 priv->sspa_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa_mux", 257 sspa_mux_parents, &clk_mux_ops, 258 CLK_SET_RATE_PARENT); 259 priv->sspa_mux.reg = priv->mmio_base + SSPA_AUD_CTRL; 260 priv->sspa_mux.mask = 1; 261 priv->sspa_mux.shift = SSPA_AUD_CTRL_SSPA0_MUX_SHIFT; 262 ret = devm_clk_hw_register(dev, &priv->sspa_mux.hw); 263 if (ret) 264 return ret; 265 266 priv->sysclk_div.hw.init = CLK_HW_INIT_HW("sys_div", 267 &priv->sspa_mux.hw, &clk_divider_ops, 268 CLK_SET_RATE_PARENT); 269 priv->sysclk_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 270 priv->sysclk_div.shift = SSPA_AUD_CTRL_SYSCLK_DIV_SHIFT; 271 priv->sysclk_div.width = 6; 272 priv->sysclk_div.flags = CLK_DIVIDER_ONE_BASED; 273 priv->sysclk_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 274 priv->sysclk_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 275 ret = devm_clk_hw_register(dev, &priv->sysclk_div.hw); 276 if (ret) 277 return ret; 278 279 priv->sysclk_gate.hw.init = CLK_HW_INIT_HW("sys_clk", 280 &priv->sysclk_div.hw, &clk_gate_ops, 281 CLK_SET_RATE_PARENT); 282 priv->sysclk_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 283 priv->sysclk_gate.bit_idx = SSPA_AUD_CTRL_SYSCLK_SHIFT; 284 ret = devm_clk_hw_register(dev, &priv->sysclk_gate.hw); 285 if (ret) 286 return ret; 287 288 priv->sspa0_div.hw.init = CLK_HW_INIT_HW("sspa0_div", 289 &priv->sspa_mux.hw, &clk_divider_ops, 0); 290 priv->sspa0_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 291 priv->sspa0_div.shift = SSPA_AUD_CTRL_SSPA0_DIV_SHIFT; 292 priv->sspa0_div.width = 6; 293 priv->sspa0_div.flags = CLK_DIVIDER_ONE_BASED; 294 priv->sspa0_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 295 priv->sspa0_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 296 ret = devm_clk_hw_register(dev, &priv->sspa0_div.hw); 297 if (ret) 298 return ret; 299 300 priv->sspa0_gate.hw.init = CLK_HW_INIT_HW("sspa0_clk", 301 &priv->sspa0_div.hw, &clk_gate_ops, 302 CLK_SET_RATE_PARENT); 303 priv->sspa0_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 304 priv->sspa0_gate.bit_idx = SSPA_AUD_CTRL_SSPA0_SHIFT; 305 ret = devm_clk_hw_register(dev, &priv->sspa0_gate.hw); 306 if (ret) 307 return ret; 308 309 priv->sspa1_mux.hw.init = CLK_HW_INIT_PARENTS_DATA("sspa1_mux", 310 sspa1_mux_parents, &clk_mux_ops, 311 CLK_SET_RATE_PARENT); 312 priv->sspa1_mux.reg = priv->mmio_base + SSPA_AUD_CTRL; 313 priv->sspa1_mux.mask = 1; 314 priv->sspa1_mux.shift = SSPA_AUD_CTRL_SSPA1_MUX_SHIFT; 315 ret = devm_clk_hw_register(dev, &priv->sspa1_mux.hw); 316 if (ret) 317 return ret; 318 319 priv->sspa1_div.hw.init = CLK_HW_INIT_HW("sspa1_div", 320 &priv->sspa1_mux.hw, &clk_divider_ops, 0); 321 priv->sspa1_div.reg = priv->mmio_base + SSPA_AUD_CTRL; 322 priv->sspa1_div.shift = SSPA_AUD_CTRL_SSPA1_DIV_SHIFT; 323 priv->sspa1_div.width = 6; 324 priv->sspa1_div.flags = CLK_DIVIDER_ONE_BASED; 325 priv->sspa1_div.flags |= CLK_DIVIDER_ROUND_CLOSEST; 326 priv->sspa1_div.flags |= CLK_DIVIDER_ALLOW_ZERO; 327 ret = devm_clk_hw_register(dev, &priv->sspa1_div.hw); 328 if (ret) 329 return ret; 330 331 priv->sspa1_gate.hw.init = CLK_HW_INIT_HW("sspa1_clk", 332 &priv->sspa1_div.hw, &clk_gate_ops, 333 CLK_SET_RATE_PARENT); 334 priv->sspa1_gate.reg = priv->mmio_base + SSPA_AUD_CTRL; 335 priv->sspa1_gate.bit_idx = SSPA_AUD_CTRL_SSPA1_SHIFT; 336 ret = devm_clk_hw_register(dev, &priv->sspa1_gate.hw); 337 if (ret) 338 return ret; 339 340 priv->clk_data.hws[MMP2_CLK_AUDIO_SYSCLK] = &priv->sysclk_gate.hw; 341 priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA0] = &priv->sspa0_gate.hw; 342 priv->clk_data.hws[MMP2_CLK_AUDIO_SSPA1] = &priv->sspa1_gate.hw; 343 priv->clk_data.num = CLK_AUDIO_NR_CLKS; 344 345 return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, 346 &priv->clk_data); 347 } 348 349 static int mmp2_audio_clk_probe(struct platform_device *pdev) 350 { 351 struct mmp2_audio_clk *priv; 352 int ret; 353 354 priv = devm_kzalloc(&pdev->dev, 355 struct_size(priv, clk_data.hws, 356 CLK_AUDIO_NR_CLKS), 357 GFP_KERNEL); 358 if (!priv) 359 return -ENOMEM; 360 361 spin_lock_init(&priv->lock); 362 platform_set_drvdata(pdev, priv); 363 364 priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); 365 if (IS_ERR(priv->mmio_base)) 366 return PTR_ERR(priv->mmio_base); 367 368 pm_runtime_enable(&pdev->dev); 369 ret = pm_clk_create(&pdev->dev); 370 if (ret) 371 goto disable_pm_runtime; 372 373 ret = pm_clk_add(&pdev->dev, "audio"); 374 if (ret) 375 goto destroy_pm_clk; 376 377 ret = register_clocks(priv, &pdev->dev); 378 if (ret) 379 goto destroy_pm_clk; 380 381 return 0; 382 383 destroy_pm_clk: 384 pm_clk_destroy(&pdev->dev); 385 disable_pm_runtime: 386 pm_runtime_disable(&pdev->dev); 387 388 return ret; 389 } 390 391 static void mmp2_audio_clk_remove(struct platform_device *pdev) 392 { 393 pm_clk_destroy(&pdev->dev); 394 pm_runtime_disable(&pdev->dev); 395 } 396 397 #ifdef CONFIG_PM 398 static int mmp2_audio_clk_suspend(struct device *dev) 399 { 400 struct mmp2_audio_clk *priv = dev_get_drvdata(dev); 401 402 priv->aud_ctrl = readl(priv->mmio_base + SSPA_AUD_CTRL); 403 priv->aud_pll_ctrl0 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL0); 404 priv->aud_pll_ctrl1 = readl(priv->mmio_base + SSPA_AUD_PLL_CTRL1); 405 pm_clk_suspend(dev); 406 407 return 0; 408 } 409 410 static int mmp2_audio_clk_resume(struct device *dev) 411 { 412 struct mmp2_audio_clk *priv = dev_get_drvdata(dev); 413 414 pm_clk_resume(dev); 415 writel(priv->aud_ctrl, priv->mmio_base + SSPA_AUD_CTRL); 416 writel(priv->aud_pll_ctrl0, priv->mmio_base + SSPA_AUD_PLL_CTRL0); 417 writel(priv->aud_pll_ctrl1, priv->mmio_base + SSPA_AUD_PLL_CTRL1); 418 419 return 0; 420 } 421 #endif 422 423 static const struct dev_pm_ops mmp2_audio_clk_pm_ops = { 424 SET_RUNTIME_PM_OPS(mmp2_audio_clk_suspend, mmp2_audio_clk_resume, NULL) 425 }; 426 427 static const struct of_device_id mmp2_audio_clk_of_match[] = { 428 { .compatible = "marvell,mmp2-audio-clock" }, 429 {} 430 }; 431 432 MODULE_DEVICE_TABLE(of, mmp2_audio_clk_of_match); 433 434 static struct platform_driver mmp2_audio_clk_driver = { 435 .driver = { 436 .name = "mmp2-audio-clock", 437 .of_match_table = of_match_ptr(mmp2_audio_clk_of_match), 438 .pm = &mmp2_audio_clk_pm_ops, 439 }, 440 .probe = mmp2_audio_clk_probe, 441 .remove = mmp2_audio_clk_remove, 442 }; 443 module_platform_driver(mmp2_audio_clk_driver); 444 445 MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); 446 MODULE_DESCRIPTION("Clock driver for MMP2 Audio subsystem"); 447 MODULE_LICENSE("GPL"); 448