Skip to content

Commit c6f2ddd

Browse files
ConchuODclaudiubeznea
authored andcommitted
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 4da2404 ("clk: microchip: mpfs: convert cfg_clk to clk_divider") and commit d815569 ("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>
1 parent eb43534 commit c6f2ddd

2 files changed

Lines changed: 186 additions & 43 deletions

File tree

drivers/clk/microchip/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ config MCHP_CLK_MPFS
77
bool "Clk driver for PolarFire SoC"
88
depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST
99
default ARCH_MICROCHIP_POLARFIRE
10+
depends on MFD_SYSCON
1011
select AUXILIARY_BUS
12+
select REGMAP_MMIO
1113
help
1214
Supports Clock Configuration for PolarFire SoC

drivers/clk/microchip/clk-mpfs.c

Lines changed: 184 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
*
55
* Copyright (C) 2020-2022 Microchip Technology Inc. All rights reserved.
66
*/
7+
#include <linux/cleanup.h>
78
#include <linux/clk-provider.h>
89
#include <linux/io.h>
10+
#include <linux/mfd/syscon.h>
911
#include <linux/module.h>
1012
#include <linux/platform_device.h>
13+
#include <linux/regmap.h>
1114
#include <dt-bindings/clock/microchip,mpfs-clock.h>
1215
#include <soc/microchip/mpfs.h>
1316

@@ -30,6 +33,14 @@
3033
#define MSSPLL_POSTDIV_WIDTH 0x07u
3134
#define MSSPLL_FIXED_DIV 4u
3235

36+
static const struct regmap_config mpfs_clk_regmap_config = {
37+
.reg_bits = 32,
38+
.reg_stride = 4,
39+
.val_bits = 32,
40+
.val_format_endian = REGMAP_ENDIAN_LITTLE,
41+
.max_register = REG_SUBBLK_CLOCK_CR,
42+
};
43+
3344
/*
3445
* This clock ID is defined here, rather than the binding headers, as it is an
3546
* internal clock only, and therefore has no consumers in other peripheral
@@ -39,6 +50,7 @@
3950

4051
struct mpfs_clock_data {
4152
struct device *dev;
53+
struct regmap *regmap;
4254
void __iomem *base;
4355
void __iomem *msspll_base;
4456
struct clk_hw_onecell_data hw_data;
@@ -67,21 +79,39 @@ struct mpfs_msspll_out_hw_clock {
6779

6880
#define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)
6981

82+
struct mpfs_cfg_clock {
83+
struct regmap *map;
84+
const struct clk_div_table *table;
85+
u8 map_offset;
86+
u8 shift;
87+
u8 width;
88+
u8 flags;
89+
};
90+
7091
struct mpfs_cfg_hw_clock {
71-
struct clk_divider cfg;
72-
struct clk_init_data init;
92+
struct clk_hw hw;
93+
struct mpfs_cfg_clock cfg;
7394
unsigned int id;
74-
u32 reg_offset;
95+
};
96+
97+
#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
98+
99+
struct mpfs_periph_clock {
100+
struct regmap *map;
101+
u8 map_offset;
102+
u8 shift;
75103
};
76104

77105
struct mpfs_periph_hw_clock {
78-
struct clk_gate periph;
106+
struct clk_hw hw;
107+
struct mpfs_periph_clock periph;
79108
unsigned int id;
80109
};
81110

111+
#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
112+
82113
/*
83-
* mpfs_clk_lock prevents anything else from writing to the
84-
* mpfs clk block while a software locked register is being written.
114+
* Protects MSSPLL outputs, since there's two to a register
85115
*/
86116
static DEFINE_SPINLOCK(mpfs_clk_lock);
87117

@@ -219,16 +249,61 @@ static int mpfs_clk_register_msspll_outs(struct device *dev,
219249
/*
220250
* "CFG" clocks
221251
*/
252+
static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
253+
{
254+
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
255+
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
256+
u32 val;
222257

223-
#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \
224-
.id = _id, \
225-
.cfg.shift = _shift, \
226-
.cfg.width = _width, \
227-
.cfg.table = _table, \
228-
.reg_offset = _offset, \
229-
.cfg.flags = _flags, \
230-
.cfg.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \
231-
.cfg.lock = &mpfs_clk_lock, \
258+
regmap_read(cfg->map, cfg->map_offset, &val);
259+
val >>= cfg->shift;
260+
val &= clk_div_mask(cfg->width);
261+
262+
return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width);
263+
}
264+
265+
static int mpfs_cfg_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
266+
{
267+
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
268+
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
269+
270+
return divider_determine_rate(hw, req, cfg->table, cfg->width, 0);
271+
}
272+
273+
static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
274+
{
275+
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
276+
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
277+
int divider_setting;
278+
u32 val;
279+
u32 mask;
280+
281+
divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0);
282+
283+
if (divider_setting < 0)
284+
return divider_setting;
285+
286+
mask = clk_div_mask(cfg->width) << cfg->shift;
287+
val = divider_setting << cfg->shift;
288+
regmap_update_bits(cfg->map, cfg->map_offset, val, mask);
289+
290+
return 0;
291+
}
292+
293+
static const struct clk_ops mpfs_clk_cfg_ops = {
294+
.recalc_rate = mpfs_cfg_clk_recalc_rate,
295+
.determine_rate = mpfs_cfg_clk_determine_rate,
296+
.set_rate = mpfs_cfg_clk_set_rate,
297+
};
298+
299+
#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \
300+
.id = _id, \
301+
.cfg.shift = _shift, \
302+
.cfg.width = _width, \
303+
.cfg.table = _table, \
304+
.cfg.map_offset = _offset, \
305+
.cfg.flags = _flags, \
306+
.hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
232307
}
233308

234309
#define CLK_CPU_OFFSET 0u
@@ -248,10 +323,10 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
248323
.cfg.shift = 0,
249324
.cfg.width = 12,
250325
.cfg.table = mpfs_div_rtcref_table,
251-
.reg_offset = REG_RTC_CLOCK_CR,
326+
.cfg.map_offset = REG_RTC_CLOCK_CR,
252327
.cfg.flags = CLK_DIVIDER_ONE_BASED,
253-
.cfg.hw.init =
254-
CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &clk_divider_ops, 0),
328+
.hw.init =
329+
CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &mpfs_clk_cfg_ops, 0),
255330
}
256331
};
257332

@@ -264,14 +339,14 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
264339
for (i = 0; i < num_clks; i++) {
265340
struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
266341

267-
cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset;
268-
ret = devm_clk_hw_register(dev, &cfg_hw->cfg.hw);
342+
cfg_hw->cfg.map = data->regmap;
343+
ret = devm_clk_hw_register(dev, &cfg_hw->hw);
269344
if (ret)
270345
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
271346
cfg_hw->id);
272347

273348
id = cfg_hw->id;
274-
data->hw_data.hws[id] = &cfg_hw->cfg.hw;
349+
data->hw_data.hws[id] = &cfg_hw->hw;
275350
}
276351

277352
return 0;
@@ -281,15 +356,50 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
281356
* peripheral clocks - devices connected to axi or ahb buses.
282357
*/
283358

284-
#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
285-
.id = _id, \
286-
.periph.bit_idx = _shift, \
287-
.periph.hw.init = CLK_HW_INIT_HW(_name, _parent, &clk_gate_ops, \
288-
_flags), \
289-
.periph.lock = &mpfs_clk_lock, \
359+
static int mpfs_periph_clk_enable(struct clk_hw *hw)
360+
{
361+
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
362+
struct mpfs_periph_clock *periph = &periph_hw->periph;
363+
364+
regmap_update_bits(periph->map, periph->map_offset,
365+
BIT(periph->shift), BIT(periph->shift));
366+
367+
return 0;
290368
}
291369

292-
#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].cfg.hw)
370+
static void mpfs_periph_clk_disable(struct clk_hw *hw)
371+
{
372+
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
373+
struct mpfs_periph_clock *periph = &periph_hw->periph;
374+
375+
regmap_update_bits(periph->map, periph->map_offset, BIT(periph->shift), 0);
376+
}
377+
378+
static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
379+
{
380+
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
381+
struct mpfs_periph_clock *periph = &periph_hw->periph;
382+
u32 val;
383+
384+
regmap_read(periph->map, periph->map_offset, &val);
385+
386+
return !!(val & BIT(periph->shift));
387+
}
388+
389+
static const struct clk_ops mpfs_periph_clk_ops = {
390+
.enable = mpfs_periph_clk_enable,
391+
.disable = mpfs_periph_clk_disable,
392+
.is_enabled = mpfs_periph_clk_is_enabled,
393+
};
394+
395+
#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
396+
.id = _id, \
397+
.periph.map_offset = REG_SUBBLK_CLOCK_CR, \
398+
.periph.shift = _shift, \
399+
.hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, _flags), \
400+
}
401+
402+
#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].hw)
293403

294404
/*
295405
* Critical clocks:
@@ -346,19 +456,55 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c
346456
for (i = 0; i < num_clks; i++) {
347457
struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
348458

349-
periph_hw->periph.reg = data->base + REG_SUBBLK_CLOCK_CR;
350-
ret = devm_clk_hw_register(dev, &periph_hw->periph.hw);
459+
periph_hw->periph.map = data->regmap;
460+
ret = devm_clk_hw_register(dev, &periph_hw->hw);
351461
if (ret)
352462
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
353463
periph_hw->id);
354464

355465
id = periph_hws[i].id;
356-
data->hw_data.hws[id] = &periph_hw->periph.hw;
466+
data->hw_data.hws[id] = &periph_hw->hw;
357467
}
358468

359469
return 0;
360470
}
361471

472+
static inline int mpfs_clk_syscon_probe(struct mpfs_clock_data *clk_data,
473+
struct platform_device *pdev)
474+
{
475+
clk_data->regmap = syscon_regmap_lookup_by_compatible("microchip,mpfs-mss-top-sysreg");
476+
if (IS_ERR(clk_data->regmap))
477+
return PTR_ERR(clk_data->regmap);
478+
479+
clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 0);
480+
if (IS_ERR(clk_data->msspll_base))
481+
return PTR_ERR(clk_data->msspll_base);
482+
483+
return 0;
484+
}
485+
486+
static inline int mpfs_clk_old_format_probe(struct mpfs_clock_data *clk_data,
487+
struct platform_device *pdev)
488+
{
489+
struct device *dev = &pdev->dev;
490+
491+
dev_warn(&pdev->dev, "falling back to old devicetree format");
492+
493+
clk_data->base = devm_platform_ioremap_resource(pdev, 0);
494+
if (IS_ERR(clk_data->base))
495+
return PTR_ERR(clk_data->base);
496+
497+
clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 1);
498+
if (IS_ERR(clk_data->msspll_base))
499+
return PTR_ERR(clk_data->msspll_base);
500+
501+
clk_data->regmap = devm_regmap_init_mmio(dev, clk_data->base, &mpfs_clk_regmap_config);
502+
if (IS_ERR(clk_data->regmap))
503+
return PTR_ERR(clk_data->regmap);
504+
505+
return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR);
506+
}
507+
362508
static int mpfs_clk_probe(struct platform_device *pdev)
363509
{
364510
struct device *dev = &pdev->dev;
@@ -374,13 +520,12 @@ static int mpfs_clk_probe(struct platform_device *pdev)
374520
if (!clk_data)
375521
return -ENOMEM;
376522

377-
clk_data->base = devm_platform_ioremap_resource(pdev, 0);
378-
if (IS_ERR(clk_data->base))
379-
return PTR_ERR(clk_data->base);
380-
381-
clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 1);
382-
if (IS_ERR(clk_data->msspll_base))
383-
return PTR_ERR(clk_data->msspll_base);
523+
ret = mpfs_clk_syscon_probe(clk_data, pdev);
524+
if (ret) {
525+
ret = mpfs_clk_old_format_probe(clk_data, pdev);
526+
if (ret)
527+
return ret;
528+
}
384529

385530
clk_data->hw_data.num = num_clks;
386531
clk_data->dev = dev;
@@ -406,11 +551,7 @@ static int mpfs_clk_probe(struct platform_device *pdev)
406551
if (ret)
407552
return ret;
408553

409-
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
410-
if (ret)
411-
return ret;
412-
413-
return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR);
554+
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
414555
}
415556

416557
static const struct of_device_id mpfs_clk_of_match_table[] = {

0 commit comments

Comments
 (0)