Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: starfive: Add StarFive JH7110 PLL clock driver

Add driver for the StarFive JH7110 PLL clock controller
and they work by reading and setting syscon registers.

Co-developed-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>

authored by

Xingyu Wu and committed by
Conor Dooley
616bc1de a097a5ec

+522
+6
MAINTAINERS
··· 20271 20271 F: Documentation/devicetree/bindings/mmc/starfive* 20272 20272 F: drivers/mmc/host/dw_mmc-starfive.c 20273 20273 20274 + STARFIVE JH7110 PLL CLOCK DRIVER 20275 + M: Xingyu Wu <xingyu.wu@starfivetech.com> 20276 + S: Supported 20277 + F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml 20278 + F: drivers/clk/starfive/clk-starfive-jh7110-pll.c 20279 + 20274 20280 STARFIVE JH7110 SYSCON 20275 20281 M: William Qiu <william.qiu@starfivetech.com> 20276 20282 M: Xingyu Wu <xingyu.wu@starfivetech.com>
+8
drivers/clk/starfive/Kconfig
··· 21 21 Say Y or M here to support the audio clocks on the StarFive JH7100 22 22 SoC. 23 23 24 + config CLK_STARFIVE_JH7110_PLL 25 + bool "StarFive JH7110 PLL clock support" 26 + depends on ARCH_STARFIVE || COMPILE_TEST 27 + default ARCH_STARFIVE 28 + help 29 + Say yes here to support the PLL clock controller on the 30 + StarFive JH7110 SoC. 31 + 24 32 config CLK_STARFIVE_JH7110_SYS 25 33 bool "StarFive JH7110 system clock support" 26 34 depends on ARCH_STARFIVE || COMPILE_TEST
+1
drivers/clk/starfive/Makefile
··· 4 4 obj-$(CONFIG_CLK_STARFIVE_JH7100) += clk-starfive-jh7100.o 5 5 obj-$(CONFIG_CLK_STARFIVE_JH7100_AUDIO) += clk-starfive-jh7100-audio.o 6 6 7 + obj-$(CONFIG_CLK_STARFIVE_JH7110_PLL) += clk-starfive-jh7110-pll.o 7 8 obj-$(CONFIG_CLK_STARFIVE_JH7110_SYS) += clk-starfive-jh7110-sys.o 8 9 obj-$(CONFIG_CLK_STARFIVE_JH7110_AON) += clk-starfive-jh7110-aon.o
+507
drivers/clk/starfive/clk-starfive-jh7110-pll.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * StarFive JH7110 PLL Clock Generator Driver 4 + * 5 + * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 + * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> 7 + * 8 + * This driver is about to register JH7110 PLL clock generator and support ops. 9 + * The JH7110 have three PLL clock, PLL0, PLL1 and PLL2. 10 + * Each PLL clocks work in integer mode or fraction mode by some dividers, 11 + * and the configuration registers and dividers are set in several syscon registers. 12 + * The formula for calculating frequency is: 13 + * Fvco = Fref * (NI + NF) / M / Q1 14 + * Fref: OSC source clock rate 15 + * NI: integer frequency dividing ratio of feedback divider, set by fbdiv[11:0]. 16 + * NF: fractional frequency dividing ratio, set by frac[23:0]. NF = frac[23:0] / 2^24 = 0 ~ 0.999. 17 + * M: frequency dividing ratio of pre-divider, set by prediv[5:0]. 18 + * Q1: frequency dividing ratio of post divider, set by 2^postdiv1[1:0], eg. 1, 2, 4 or 8. 19 + */ 20 + 21 + #include <linux/bits.h> 22 + #include <linux/clk-provider.h> 23 + #include <linux/debugfs.h> 24 + #include <linux/device.h> 25 + #include <linux/kernel.h> 26 + #include <linux/mfd/syscon.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/regmap.h> 29 + 30 + #include <dt-bindings/clock/starfive,jh7110-crg.h> 31 + 32 + /* this driver expects a 24MHz input frequency from the oscillator */ 33 + #define JH7110_PLL_OSC_RATE 24000000UL 34 + 35 + #define JH7110_PLL0_PD_OFFSET 0x18 36 + #define JH7110_PLL0_DACPD_SHIFT 24 37 + #define JH7110_PLL0_DACPD_MASK BIT(24) 38 + #define JH7110_PLL0_DSMPD_SHIFT 25 39 + #define JH7110_PLL0_DSMPD_MASK BIT(25) 40 + #define JH7110_PLL0_FBDIV_OFFSET 0x1c 41 + #define JH7110_PLL0_FBDIV_SHIFT 0 42 + #define JH7110_PLL0_FBDIV_MASK GENMASK(11, 0) 43 + #define JH7110_PLL0_FRAC_OFFSET 0x20 44 + #define JH7110_PLL0_PREDIV_OFFSET 0x24 45 + 46 + #define JH7110_PLL1_PD_OFFSET 0x24 47 + #define JH7110_PLL1_DACPD_SHIFT 15 48 + #define JH7110_PLL1_DACPD_MASK BIT(15) 49 + #define JH7110_PLL1_DSMPD_SHIFT 16 50 + #define JH7110_PLL1_DSMPD_MASK BIT(16) 51 + #define JH7110_PLL1_FBDIV_OFFSET 0x24 52 + #define JH7110_PLL1_FBDIV_SHIFT 17 53 + #define JH7110_PLL1_FBDIV_MASK GENMASK(28, 17) 54 + #define JH7110_PLL1_FRAC_OFFSET 0x28 55 + #define JH7110_PLL1_PREDIV_OFFSET 0x2c 56 + 57 + #define JH7110_PLL2_PD_OFFSET 0x2c 58 + #define JH7110_PLL2_DACPD_SHIFT 15 59 + #define JH7110_PLL2_DACPD_MASK BIT(15) 60 + #define JH7110_PLL2_DSMPD_SHIFT 16 61 + #define JH7110_PLL2_DSMPD_MASK BIT(16) 62 + #define JH7110_PLL2_FBDIV_OFFSET 0x2c 63 + #define JH7110_PLL2_FBDIV_SHIFT 17 64 + #define JH7110_PLL2_FBDIV_MASK GENMASK(28, 17) 65 + #define JH7110_PLL2_FRAC_OFFSET 0x30 66 + #define JH7110_PLL2_PREDIV_OFFSET 0x34 67 + 68 + #define JH7110_PLL_FRAC_SHIFT 0 69 + #define JH7110_PLL_FRAC_MASK GENMASK(23, 0) 70 + #define JH7110_PLL_POSTDIV1_SHIFT 28 71 + #define JH7110_PLL_POSTDIV1_MASK GENMASK(29, 28) 72 + #define JH7110_PLL_PREDIV_SHIFT 0 73 + #define JH7110_PLL_PREDIV_MASK GENMASK(5, 0) 74 + 75 + enum jh7110_pll_mode { 76 + JH7110_PLL_MODE_FRACTION, 77 + JH7110_PLL_MODE_INTEGER, 78 + }; 79 + 80 + struct jh7110_pll_preset { 81 + unsigned long freq; 82 + u32 frac; /* frac value should be decimals multiplied by 2^24 */ 83 + unsigned fbdiv : 12; /* fbdiv value should be 8 to 4095 */ 84 + unsigned prediv : 6; 85 + unsigned postdiv1 : 2; 86 + unsigned mode : 1; 87 + }; 88 + 89 + struct jh7110_pll_info { 90 + char *name; 91 + const struct jh7110_pll_preset *presets; 92 + unsigned int npresets; 93 + struct { 94 + unsigned int pd; 95 + unsigned int fbdiv; 96 + unsigned int frac; 97 + unsigned int prediv; 98 + } offsets; 99 + struct { 100 + u32 dacpd; 101 + u32 dsmpd; 102 + u32 fbdiv; 103 + } masks; 104 + struct { 105 + char dacpd; 106 + char dsmpd; 107 + char fbdiv; 108 + } shifts; 109 + }; 110 + 111 + #define _JH7110_PLL(_idx, _name, _presets) \ 112 + [_idx] = { \ 113 + .name = _name, \ 114 + .presets = _presets, \ 115 + .npresets = ARRAY_SIZE(_presets), \ 116 + .offsets = { \ 117 + .pd = JH7110_PLL##_idx##_PD_OFFSET, \ 118 + .fbdiv = JH7110_PLL##_idx##_FBDIV_OFFSET, \ 119 + .frac = JH7110_PLL##_idx##_FRAC_OFFSET, \ 120 + .prediv = JH7110_PLL##_idx##_PREDIV_OFFSET, \ 121 + }, \ 122 + .masks = { \ 123 + .dacpd = JH7110_PLL##_idx##_DACPD_MASK, \ 124 + .dsmpd = JH7110_PLL##_idx##_DSMPD_MASK, \ 125 + .fbdiv = JH7110_PLL##_idx##_FBDIV_MASK, \ 126 + }, \ 127 + .shifts = { \ 128 + .dacpd = JH7110_PLL##_idx##_DACPD_SHIFT, \ 129 + .dsmpd = JH7110_PLL##_idx##_DSMPD_SHIFT, \ 130 + .fbdiv = JH7110_PLL##_idx##_FBDIV_SHIFT, \ 131 + }, \ 132 + } 133 + #define JH7110_PLL(idx, name, presets) _JH7110_PLL(idx, name, presets) 134 + 135 + struct jh7110_pll_data { 136 + struct clk_hw hw; 137 + unsigned int idx; 138 + }; 139 + 140 + struct jh7110_pll_priv { 141 + struct device *dev; 142 + struct regmap *regmap; 143 + struct jh7110_pll_data pll[JH7110_PLLCLK_END]; 144 + }; 145 + 146 + struct jh7110_pll_regvals { 147 + u32 dacpd; 148 + u32 dsmpd; 149 + u32 fbdiv; 150 + u32 frac; 151 + u32 postdiv1; 152 + u32 prediv; 153 + }; 154 + 155 + /* 156 + * Because the pll frequency is relatively fixed, 157 + * it cannot be set arbitrarily, so it needs a specific configuration. 158 + * PLL0 frequency should be multiple of 125MHz (USB frequency). 159 + */ 160 + static const struct jh7110_pll_preset jh7110_pll0_presets[] = { 161 + { 162 + .freq = 375000000, 163 + .fbdiv = 125, 164 + .prediv = 8, 165 + .postdiv1 = 0, 166 + .mode = JH7110_PLL_MODE_INTEGER, 167 + }, { 168 + .freq = 500000000, 169 + .fbdiv = 125, 170 + .prediv = 6, 171 + .postdiv1 = 0, 172 + .mode = JH7110_PLL_MODE_INTEGER, 173 + }, { 174 + .freq = 625000000, 175 + .fbdiv = 625, 176 + .prediv = 24, 177 + .postdiv1 = 0, 178 + .mode = JH7110_PLL_MODE_INTEGER, 179 + }, { 180 + .freq = 750000000, 181 + .fbdiv = 125, 182 + .prediv = 4, 183 + .postdiv1 = 0, 184 + .mode = JH7110_PLL_MODE_INTEGER, 185 + }, { 186 + .freq = 875000000, 187 + .fbdiv = 875, 188 + .prediv = 24, 189 + .postdiv1 = 0, 190 + .mode = JH7110_PLL_MODE_INTEGER, 191 + }, { 192 + .freq = 1000000000, 193 + .fbdiv = 125, 194 + .prediv = 3, 195 + .postdiv1 = 0, 196 + .mode = JH7110_PLL_MODE_INTEGER, 197 + }, { 198 + .freq = 1250000000, 199 + .fbdiv = 625, 200 + .prediv = 12, 201 + .postdiv1 = 0, 202 + .mode = JH7110_PLL_MODE_INTEGER, 203 + }, { 204 + .freq = 1375000000, 205 + .fbdiv = 1375, 206 + .prediv = 24, 207 + .postdiv1 = 0, 208 + .mode = JH7110_PLL_MODE_INTEGER, 209 + }, { 210 + .freq = 1500000000, 211 + .fbdiv = 125, 212 + .prediv = 2, 213 + .postdiv1 = 0, 214 + .mode = JH7110_PLL_MODE_INTEGER, 215 + }, 216 + }; 217 + 218 + static const struct jh7110_pll_preset jh7110_pll1_presets[] = { 219 + { 220 + .freq = 1066000000, 221 + .fbdiv = 533, 222 + .prediv = 12, 223 + .postdiv1 = 0, 224 + .mode = JH7110_PLL_MODE_INTEGER, 225 + }, { 226 + .freq = 1200000000, 227 + .fbdiv = 50, 228 + .prediv = 1, 229 + .postdiv1 = 0, 230 + .mode = JH7110_PLL_MODE_INTEGER, 231 + }, { 232 + .freq = 1400000000, 233 + .fbdiv = 350, 234 + .prediv = 6, 235 + .postdiv1 = 0, 236 + .mode = JH7110_PLL_MODE_INTEGER, 237 + }, { 238 + .freq = 1600000000, 239 + .fbdiv = 200, 240 + .prediv = 3, 241 + .postdiv1 = 0, 242 + .mode = JH7110_PLL_MODE_INTEGER, 243 + }, 244 + }; 245 + 246 + static const struct jh7110_pll_preset jh7110_pll2_presets[] = { 247 + { 248 + .freq = 1188000000, 249 + .fbdiv = 99, 250 + .prediv = 2, 251 + .postdiv1 = 0, 252 + .mode = JH7110_PLL_MODE_INTEGER, 253 + }, { 254 + .freq = 1228800000, 255 + .fbdiv = 256, 256 + .prediv = 5, 257 + .postdiv1 = 0, 258 + .mode = JH7110_PLL_MODE_INTEGER, 259 + }, 260 + }; 261 + 262 + static const struct jh7110_pll_info jh7110_plls[JH7110_PLLCLK_END] = { 263 + JH7110_PLL(JH7110_PLLCLK_PLL0_OUT, "pll0_out", jh7110_pll0_presets), 264 + JH7110_PLL(JH7110_PLLCLK_PLL1_OUT, "pll1_out", jh7110_pll1_presets), 265 + JH7110_PLL(JH7110_PLLCLK_PLL2_OUT, "pll2_out", jh7110_pll2_presets), 266 + }; 267 + 268 + static struct jh7110_pll_data *jh7110_pll_data_from(struct clk_hw *hw) 269 + { 270 + return container_of(hw, struct jh7110_pll_data, hw); 271 + } 272 + 273 + static struct jh7110_pll_priv *jh7110_pll_priv_from(struct jh7110_pll_data *pll) 274 + { 275 + return container_of(pll, struct jh7110_pll_priv, pll[pll->idx]); 276 + } 277 + 278 + static void jh7110_pll_regvals_get(struct regmap *regmap, 279 + const struct jh7110_pll_info *info, 280 + struct jh7110_pll_regvals *ret) 281 + { 282 + u32 val; 283 + 284 + regmap_read(regmap, info->offsets.pd, &val); 285 + ret->dacpd = (val & info->masks.dacpd) >> info->shifts.dacpd; 286 + ret->dsmpd = (val & info->masks.dsmpd) >> info->shifts.dsmpd; 287 + 288 + regmap_read(regmap, info->offsets.fbdiv, &val); 289 + ret->fbdiv = (val & info->masks.fbdiv) >> info->shifts.fbdiv; 290 + 291 + regmap_read(regmap, info->offsets.frac, &val); 292 + ret->frac = (val & JH7110_PLL_FRAC_MASK) >> JH7110_PLL_FRAC_SHIFT; 293 + ret->postdiv1 = (val & JH7110_PLL_POSTDIV1_MASK) >> JH7110_PLL_POSTDIV1_SHIFT; 294 + 295 + regmap_read(regmap, info->offsets.prediv, &val); 296 + ret->prediv = (val & JH7110_PLL_PREDIV_MASK) >> JH7110_PLL_PREDIV_SHIFT; 297 + } 298 + 299 + static unsigned long jh7110_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 300 + { 301 + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); 302 + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); 303 + struct jh7110_pll_regvals val; 304 + unsigned long rate; 305 + 306 + jh7110_pll_regvals_get(priv->regmap, &jh7110_plls[pll->idx], &val); 307 + 308 + /* 309 + * dacpd = dsmpd = 0: fraction mode 310 + * dacpd = dsmpd = 1: integer mode, frac value ignored 311 + * 312 + * rate = parent * (fbdiv + frac/2^24) / prediv / 2^postdiv1 313 + * = (parent * fbdiv + parent * frac / 2^24) / (prediv * 2^postdiv1) 314 + */ 315 + if (val.dacpd == 0 && val.dsmpd == 0) 316 + rate = parent_rate * val.frac / (1UL << 24); 317 + else if (val.dacpd == 1 && val.dsmpd == 1) 318 + rate = 0; 319 + else 320 + return 0; 321 + 322 + rate += parent_rate * val.fbdiv; 323 + rate /= val.prediv << val.postdiv1; 324 + 325 + return rate; 326 + } 327 + 328 + static int jh7110_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 329 + { 330 + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); 331 + const struct jh7110_pll_info *info = &jh7110_plls[pll->idx]; 332 + const struct jh7110_pll_preset *selected = &info->presets[0]; 333 + unsigned int idx; 334 + 335 + /* if the parent rate doesn't match our expectations the presets won't work */ 336 + if (req->best_parent_rate != JH7110_PLL_OSC_RATE) { 337 + req->rate = jh7110_pll_recalc_rate(hw, req->best_parent_rate); 338 + return 0; 339 + } 340 + 341 + /* find highest rate lower or equal to the requested rate */ 342 + for (idx = 1; idx < info->npresets; idx++) { 343 + const struct jh7110_pll_preset *val = &info->presets[idx]; 344 + 345 + if (req->rate < val->freq) 346 + break; 347 + 348 + selected = val; 349 + } 350 + 351 + req->rate = selected->freq; 352 + return 0; 353 + } 354 + 355 + static int jh7110_pll_set_rate(struct clk_hw *hw, unsigned long rate, 356 + unsigned long parent_rate) 357 + { 358 + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); 359 + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); 360 + const struct jh7110_pll_info *info = &jh7110_plls[pll->idx]; 361 + const struct jh7110_pll_preset *val; 362 + unsigned int idx; 363 + 364 + /* if the parent rate doesn't match our expectations the presets won't work */ 365 + if (parent_rate != JH7110_PLL_OSC_RATE) 366 + return -EINVAL; 367 + 368 + for (idx = 0, val = &info->presets[0]; idx < info->npresets; idx++, val++) { 369 + if (val->freq == rate) 370 + goto found; 371 + } 372 + return -EINVAL; 373 + 374 + found: 375 + if (val->mode == JH7110_PLL_MODE_FRACTION) 376 + regmap_update_bits(priv->regmap, info->offsets.frac, JH7110_PLL_FRAC_MASK, 377 + val->frac << JH7110_PLL_FRAC_SHIFT); 378 + 379 + regmap_update_bits(priv->regmap, info->offsets.pd, info->masks.dacpd, 380 + (u32)val->mode << info->shifts.dacpd); 381 + regmap_update_bits(priv->regmap, info->offsets.pd, info->masks.dsmpd, 382 + (u32)val->mode << info->shifts.dsmpd); 383 + regmap_update_bits(priv->regmap, info->offsets.prediv, JH7110_PLL_PREDIV_MASK, 384 + (u32)val->prediv << JH7110_PLL_PREDIV_SHIFT); 385 + regmap_update_bits(priv->regmap, info->offsets.fbdiv, info->masks.fbdiv, 386 + val->fbdiv << info->shifts.fbdiv); 387 + regmap_update_bits(priv->regmap, info->offsets.frac, JH7110_PLL_POSTDIV1_MASK, 388 + (u32)val->postdiv1 << JH7110_PLL_POSTDIV1_SHIFT); 389 + 390 + return 0; 391 + } 392 + 393 + #ifdef CONFIG_DEBUG_FS 394 + static int jh7110_pll_registers_read(struct seq_file *s, void *unused) 395 + { 396 + struct jh7110_pll_data *pll = s->private; 397 + struct jh7110_pll_priv *priv = jh7110_pll_priv_from(pll); 398 + struct jh7110_pll_regvals val; 399 + 400 + jh7110_pll_regvals_get(priv->regmap, &jh7110_plls[pll->idx], &val); 401 + 402 + seq_printf(s, "fbdiv=%u\n" 403 + "frac=%u\n" 404 + "prediv=%u\n" 405 + "postdiv1=%u\n" 406 + "dacpd=%u\n" 407 + "dsmpd=%u\n", 408 + val.fbdiv, val.frac, val.prediv, val.postdiv1, 409 + val.dacpd, val.dsmpd); 410 + 411 + return 0; 412 + } 413 + 414 + static int jh7110_pll_registers_open(struct inode *inode, struct file *f) 415 + { 416 + return single_open(f, jh7110_pll_registers_read, inode->i_private); 417 + } 418 + 419 + static const struct file_operations jh7110_pll_registers_ops = { 420 + .owner = THIS_MODULE, 421 + .open = jh7110_pll_registers_open, 422 + .release = single_release, 423 + .read = seq_read, 424 + .llseek = seq_lseek 425 + }; 426 + 427 + static void jh7110_pll_debug_init(struct clk_hw *hw, struct dentry *dentry) 428 + { 429 + struct jh7110_pll_data *pll = jh7110_pll_data_from(hw); 430 + 431 + debugfs_create_file("registers", 0400, dentry, pll, 432 + &jh7110_pll_registers_ops); 433 + } 434 + #else 435 + #define jh7110_pll_debug_init NULL 436 + #endif 437 + 438 + static const struct clk_ops jh7110_pll_ops = { 439 + .recalc_rate = jh7110_pll_recalc_rate, 440 + .determine_rate = jh7110_pll_determine_rate, 441 + .set_rate = jh7110_pll_set_rate, 442 + .debug_init = jh7110_pll_debug_init, 443 + }; 444 + 445 + static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data) 446 + { 447 + struct jh7110_pll_priv *priv = data; 448 + unsigned int idx = clkspec->args[0]; 449 + 450 + if (idx < JH7110_PLLCLK_END) 451 + return &priv->pll[idx].hw; 452 + 453 + return ERR_PTR(-EINVAL); 454 + } 455 + 456 + static int jh7110_pll_probe(struct platform_device *pdev) 457 + { 458 + struct jh7110_pll_priv *priv; 459 + unsigned int idx; 460 + int ret; 461 + 462 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 463 + if (!priv) 464 + return -ENOMEM; 465 + 466 + priv->dev = &pdev->dev; 467 + priv->regmap = syscon_node_to_regmap(priv->dev->of_node->parent); 468 + if (IS_ERR(priv->regmap)) 469 + return PTR_ERR(priv->regmap); 470 + 471 + for (idx = 0; idx < JH7110_PLLCLK_END; idx++) { 472 + struct clk_parent_data parents = { 473 + .index = 0, 474 + }; 475 + struct clk_init_data init = { 476 + .name = jh7110_plls[idx].name, 477 + .ops = &jh7110_pll_ops, 478 + .parent_data = &parents, 479 + .num_parents = 1, 480 + .flags = 0, 481 + }; 482 + struct jh7110_pll_data *pll = &priv->pll[idx]; 483 + 484 + pll->hw.init = &init; 485 + pll->idx = idx; 486 + 487 + ret = devm_clk_hw_register(&pdev->dev, &pll->hw); 488 + if (ret) 489 + return ret; 490 + } 491 + 492 + return devm_of_clk_add_hw_provider(&pdev->dev, jh7110_pll_get, priv); 493 + } 494 + 495 + static const struct of_device_id jh7110_pll_match[] = { 496 + { .compatible = "starfive,jh7110-pll" }, 497 + { /* sentinel */ } 498 + }; 499 + MODULE_DEVICE_TABLE(of, jh7110_pll_match); 500 + 501 + static struct platform_driver jh7110_pll_driver = { 502 + .driver = { 503 + .name = "clk-starfive-jh7110-pll", 504 + .of_match_table = jh7110_pll_match, 505 + }, 506 + }; 507 + builtin_platform_driver_probe(jh7110_pll_driver, jh7110_pll_probe);