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

clk: microchip: mpfs: use regmap for clocks

Convert the PolarFire SoC clock driver to use regmaps instead of iomem
addresses as a preparatory work for supporting the new binding for this
device that will only provide the second of the two register regions, and
will require the use of syscon regmap to access the "cfg" and "periph"
clocks currently supported by the driver.

This is effectively a revert of commit 4da2404bb003 ("clk: microchip:
mpfs: convert cfg_clk to clk_divider") and commit d815569783e6 ("clk:
microchip: mpfs: convert periph_clk to clk_gate") as it resurrects the
ops structures removed in those commits, with the readl()s and
writel()s replaced by regmap_read()s and regmap_writes()s.

Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Link: https://lore.kernel.org/r/20251029-surfboard-refocus-ca9b135ab123@spud
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>

authored by

Conor Dooley and committed by
Claudiu Beznea
c6f2dddf eb43534e

+186 -43
+2
drivers/clk/microchip/Kconfig
··· 7 7 bool "Clk driver for PolarFire SoC" 8 8 depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST 9 9 default ARCH_MICROCHIP_POLARFIRE 10 + depends on MFD_SYSCON 10 11 select AUXILIARY_BUS 12 + select REGMAP_MMIO 11 13 help 12 14 Supports Clock Configuration for PolarFire SoC
+184 -43
drivers/clk/microchip/clk-mpfs.c
··· 4 4 * 5 5 * Copyright (C) 2020-2022 Microchip Technology Inc. All rights reserved. 6 6 */ 7 + #include <linux/cleanup.h> 7 8 #include <linux/clk-provider.h> 8 9 #include <linux/io.h> 10 + #include <linux/mfd/syscon.h> 9 11 #include <linux/module.h> 10 12 #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 11 14 #include <dt-bindings/clock/microchip,mpfs-clock.h> 12 15 #include <soc/microchip/mpfs.h> 13 16 ··· 33 30 #define MSSPLL_POSTDIV_WIDTH 0x07u 34 31 #define MSSPLL_FIXED_DIV 4u 35 32 33 + static const struct regmap_config mpfs_clk_regmap_config = { 34 + .reg_bits = 32, 35 + .reg_stride = 4, 36 + .val_bits = 32, 37 + .val_format_endian = REGMAP_ENDIAN_LITTLE, 38 + .max_register = REG_SUBBLK_CLOCK_CR, 39 + }; 40 + 36 41 /* 37 42 * This clock ID is defined here, rather than the binding headers, as it is an 38 43 * internal clock only, and therefore has no consumers in other peripheral ··· 50 39 51 40 struct mpfs_clock_data { 52 41 struct device *dev; 42 + struct regmap *regmap; 53 43 void __iomem *base; 54 44 void __iomem *msspll_base; 55 45 struct clk_hw_onecell_data hw_data; ··· 79 67 80 68 #define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw) 81 69 70 + struct mpfs_cfg_clock { 71 + struct regmap *map; 72 + const struct clk_div_table *table; 73 + u8 map_offset; 74 + u8 shift; 75 + u8 width; 76 + u8 flags; 77 + }; 78 + 82 79 struct mpfs_cfg_hw_clock { 83 - struct clk_divider cfg; 84 - struct clk_init_data init; 80 + struct clk_hw hw; 81 + struct mpfs_cfg_clock cfg; 85 82 unsigned int id; 86 - u32 reg_offset; 83 + }; 84 + 85 + #define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw) 86 + 87 + struct mpfs_periph_clock { 88 + struct regmap *map; 89 + u8 map_offset; 90 + u8 shift; 87 91 }; 88 92 89 93 struct mpfs_periph_hw_clock { 90 - struct clk_gate periph; 94 + struct clk_hw hw; 95 + struct mpfs_periph_clock periph; 91 96 unsigned int id; 92 97 }; 93 98 99 + #define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw) 100 + 94 101 /* 95 - * mpfs_clk_lock prevents anything else from writing to the 96 - * mpfs clk block while a software locked register is being written. 102 + * Protects MSSPLL outputs, since there's two to a register 97 103 */ 98 104 static DEFINE_SPINLOCK(mpfs_clk_lock); 99 105 ··· 249 219 /* 250 220 * "CFG" clocks 251 221 */ 222 + static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate) 223 + { 224 + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 225 + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 226 + u32 val; 252 227 253 - #define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \ 254 - .id = _id, \ 255 - .cfg.shift = _shift, \ 256 - .cfg.width = _width, \ 257 - .cfg.table = _table, \ 258 - .reg_offset = _offset, \ 259 - .cfg.flags = _flags, \ 260 - .cfg.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \ 261 - .cfg.lock = &mpfs_clk_lock, \ 228 + regmap_read(cfg->map, cfg->map_offset, &val); 229 + val >>= cfg->shift; 230 + val &= clk_div_mask(cfg->width); 231 + 232 + return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width); 233 + } 234 + 235 + static int mpfs_cfg_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 236 + { 237 + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 238 + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 239 + 240 + return divider_determine_rate(hw, req, cfg->table, cfg->width, 0); 241 + } 242 + 243 + static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) 244 + { 245 + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 246 + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 247 + int divider_setting; 248 + u32 val; 249 + u32 mask; 250 + 251 + divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0); 252 + 253 + if (divider_setting < 0) 254 + return divider_setting; 255 + 256 + mask = clk_div_mask(cfg->width) << cfg->shift; 257 + val = divider_setting << cfg->shift; 258 + regmap_update_bits(cfg->map, cfg->map_offset, val, mask); 259 + 260 + return 0; 261 + } 262 + 263 + static const struct clk_ops mpfs_clk_cfg_ops = { 264 + .recalc_rate = mpfs_cfg_clk_recalc_rate, 265 + .determine_rate = mpfs_cfg_clk_determine_rate, 266 + .set_rate = mpfs_cfg_clk_set_rate, 267 + }; 268 + 269 + #define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \ 270 + .id = _id, \ 271 + .cfg.shift = _shift, \ 272 + .cfg.width = _width, \ 273 + .cfg.table = _table, \ 274 + .cfg.map_offset = _offset, \ 275 + .cfg.flags = _flags, \ 276 + .hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \ 262 277 } 263 278 264 279 #define CLK_CPU_OFFSET 0u ··· 323 248 .cfg.shift = 0, 324 249 .cfg.width = 12, 325 250 .cfg.table = mpfs_div_rtcref_table, 326 - .reg_offset = REG_RTC_CLOCK_CR, 251 + .cfg.map_offset = REG_RTC_CLOCK_CR, 327 252 .cfg.flags = CLK_DIVIDER_ONE_BASED, 328 - .cfg.hw.init = 329 - CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &clk_divider_ops, 0), 253 + .hw.init = 254 + CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &mpfs_clk_cfg_ops, 0), 330 255 } 331 256 }; 332 257 ··· 339 264 for (i = 0; i < num_clks; i++) { 340 265 struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i]; 341 266 342 - cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset; 343 - ret = devm_clk_hw_register(dev, &cfg_hw->cfg.hw); 267 + cfg_hw->cfg.map = data->regmap; 268 + ret = devm_clk_hw_register(dev, &cfg_hw->hw); 344 269 if (ret) 345 270 return dev_err_probe(dev, ret, "failed to register clock id: %d\n", 346 271 cfg_hw->id); 347 272 348 273 id = cfg_hw->id; 349 - data->hw_data.hws[id] = &cfg_hw->cfg.hw; 274 + data->hw_data.hws[id] = &cfg_hw->hw; 350 275 } 351 276 352 277 return 0; ··· 356 281 * peripheral clocks - devices connected to axi or ahb buses. 357 282 */ 358 283 359 - #define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \ 360 - .id = _id, \ 361 - .periph.bit_idx = _shift, \ 362 - .periph.hw.init = CLK_HW_INIT_HW(_name, _parent, &clk_gate_ops, \ 363 - _flags), \ 364 - .periph.lock = &mpfs_clk_lock, \ 284 + static int mpfs_periph_clk_enable(struct clk_hw *hw) 285 + { 286 + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 287 + struct mpfs_periph_clock *periph = &periph_hw->periph; 288 + 289 + regmap_update_bits(periph->map, periph->map_offset, 290 + BIT(periph->shift), BIT(periph->shift)); 291 + 292 + return 0; 365 293 } 366 294 367 - #define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].cfg.hw) 295 + static void mpfs_periph_clk_disable(struct clk_hw *hw) 296 + { 297 + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 298 + struct mpfs_periph_clock *periph = &periph_hw->periph; 299 + 300 + regmap_update_bits(periph->map, periph->map_offset, BIT(periph->shift), 0); 301 + } 302 + 303 + static int mpfs_periph_clk_is_enabled(struct clk_hw *hw) 304 + { 305 + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 306 + struct mpfs_periph_clock *periph = &periph_hw->periph; 307 + u32 val; 308 + 309 + regmap_read(periph->map, periph->map_offset, &val); 310 + 311 + return !!(val & BIT(periph->shift)); 312 + } 313 + 314 + static const struct clk_ops mpfs_periph_clk_ops = { 315 + .enable = mpfs_periph_clk_enable, 316 + .disable = mpfs_periph_clk_disable, 317 + .is_enabled = mpfs_periph_clk_is_enabled, 318 + }; 319 + 320 + #define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \ 321 + .id = _id, \ 322 + .periph.map_offset = REG_SUBBLK_CLOCK_CR, \ 323 + .periph.shift = _shift, \ 324 + .hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, _flags), \ 325 + } 326 + 327 + #define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].hw) 368 328 369 329 /* 370 330 * Critical clocks: ··· 456 346 for (i = 0; i < num_clks; i++) { 457 347 struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i]; 458 348 459 - periph_hw->periph.reg = data->base + REG_SUBBLK_CLOCK_CR; 460 - ret = devm_clk_hw_register(dev, &periph_hw->periph.hw); 349 + periph_hw->periph.map = data->regmap; 350 + ret = devm_clk_hw_register(dev, &periph_hw->hw); 461 351 if (ret) 462 352 return dev_err_probe(dev, ret, "failed to register clock id: %d\n", 463 353 periph_hw->id); 464 354 465 355 id = periph_hws[i].id; 466 - data->hw_data.hws[id] = &periph_hw->periph.hw; 356 + data->hw_data.hws[id] = &periph_hw->hw; 467 357 } 468 358 469 359 return 0; 360 + } 361 + 362 + static inline int mpfs_clk_syscon_probe(struct mpfs_clock_data *clk_data, 363 + struct platform_device *pdev) 364 + { 365 + clk_data->regmap = syscon_regmap_lookup_by_compatible("microchip,mpfs-mss-top-sysreg"); 366 + if (IS_ERR(clk_data->regmap)) 367 + return PTR_ERR(clk_data->regmap); 368 + 369 + clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 0); 370 + if (IS_ERR(clk_data->msspll_base)) 371 + return PTR_ERR(clk_data->msspll_base); 372 + 373 + return 0; 374 + } 375 + 376 + static inline int mpfs_clk_old_format_probe(struct mpfs_clock_data *clk_data, 377 + struct platform_device *pdev) 378 + { 379 + struct device *dev = &pdev->dev; 380 + 381 + dev_warn(&pdev->dev, "falling back to old devicetree format"); 382 + 383 + clk_data->base = devm_platform_ioremap_resource(pdev, 0); 384 + if (IS_ERR(clk_data->base)) 385 + return PTR_ERR(clk_data->base); 386 + 387 + clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 1); 388 + if (IS_ERR(clk_data->msspll_base)) 389 + return PTR_ERR(clk_data->msspll_base); 390 + 391 + clk_data->regmap = devm_regmap_init_mmio(dev, clk_data->base, &mpfs_clk_regmap_config); 392 + if (IS_ERR(clk_data->regmap)) 393 + return PTR_ERR(clk_data->regmap); 394 + 395 + return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR); 470 396 } 471 397 472 398 static int mpfs_clk_probe(struct platform_device *pdev) ··· 520 374 if (!clk_data) 521 375 return -ENOMEM; 522 376 523 - clk_data->base = devm_platform_ioremap_resource(pdev, 0); 524 - if (IS_ERR(clk_data->base)) 525 - return PTR_ERR(clk_data->base); 526 - 527 - clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 1); 528 - if (IS_ERR(clk_data->msspll_base)) 529 - return PTR_ERR(clk_data->msspll_base); 377 + ret = mpfs_clk_syscon_probe(clk_data, pdev); 378 + if (ret) { 379 + ret = mpfs_clk_old_format_probe(clk_data, pdev); 380 + if (ret) 381 + return ret; 382 + } 530 383 531 384 clk_data->hw_data.num = num_clks; 532 385 clk_data->dev = dev; ··· 551 406 if (ret) 552 407 return ret; 553 408 554 - ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data); 555 - if (ret) 556 - return ret; 557 - 558 - return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR); 409 + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data); 559 410 } 560 411 561 412 static const struct of_device_id mpfs_clk_of_match_table[] = {