1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
6 #include <linux/clk-provider.h>
7 #include <linux/clkdev.h>
8 #include <linux/clk/at91_pmc.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/regmap.h>
15 #define SYSTEM_MAX_ID 31
17 #define SYSTEM_MAX_NAME_SZ 32
19 #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
22 struct regmap
*regmap
;
26 static inline int is_pck(int id
)
28 return (id
>= 8) && (id
<= 15);
31 static inline bool clk_system_ready(struct regmap
*regmap
, int id
)
35 regmap_read(regmap
, AT91_PMC_SR
, &status
);
37 return !!(status
& (1 << id
));
40 static int clk_system_prepare(struct clk_hw
*hw
)
42 struct clk_system
*sys
= to_clk_system(hw
);
44 regmap_write(sys
->regmap
, AT91_PMC_SCER
, 1 << sys
->id
);
49 while (!clk_system_ready(sys
->regmap
, sys
->id
))
55 static void clk_system_unprepare(struct clk_hw
*hw
)
57 struct clk_system
*sys
= to_clk_system(hw
);
59 regmap_write(sys
->regmap
, AT91_PMC_SCDR
, 1 << sys
->id
);
62 static int clk_system_is_prepared(struct clk_hw
*hw
)
64 struct clk_system
*sys
= to_clk_system(hw
);
67 regmap_read(sys
->regmap
, AT91_PMC_SCSR
, &status
);
69 if (!(status
& (1 << sys
->id
)))
75 regmap_read(sys
->regmap
, AT91_PMC_SR
, &status
);
77 return !!(status
& (1 << sys
->id
));
80 static const struct clk_ops system_ops
= {
81 .prepare
= clk_system_prepare
,
82 .unprepare
= clk_system_unprepare
,
83 .is_prepared
= clk_system_is_prepared
,
86 struct clk_hw
* __init
87 at91_clk_register_system(struct regmap
*regmap
, const char *name
,
88 const char *parent_name
, u8 id
)
90 struct clk_system
*sys
;
92 struct clk_init_data init
;
95 if (!parent_name
|| id
> SYSTEM_MAX_ID
)
96 return ERR_PTR(-EINVAL
);
98 sys
= kzalloc(sizeof(*sys
), GFP_KERNEL
);
100 return ERR_PTR(-ENOMEM
);
103 init
.ops
= &system_ops
;
104 init
.parent_names
= &parent_name
;
105 init
.num_parents
= 1;
106 init
.flags
= CLK_SET_RATE_PARENT
;
109 sys
->hw
.init
= &init
;
110 sys
->regmap
= regmap
;
113 ret
= clk_hw_register(NULL
, &sys
->hw
);