1 // SPDX-License-Identifier: GPL-2.0
3 * R-Car Gen3 Clock Pulse Generator Library
5 * Copyright (C) 2015-2018 Glider bvba
6 * Copyright (C) 2019 Renesas Electronics Corp.
8 * Based on clk-rcar-gen3.c
10 * Copyright (C) 2015 Renesas Electronics Corp.
13 #include <linux/clk.h>
14 #include <linux/clk-provider.h>
15 #include <linux/device.h>
16 #include <linux/err.h>
17 #include <linux/init.h>
20 #include <linux/slab.h>
21 #include <linux/sys_soc.h>
23 #include "rcar-cpg-lib.h"
25 DEFINE_SPINLOCK(cpg_lock
);
27 void cpg_reg_modify(void __iomem
*reg
, u32 clear
, u32 set
)
32 spin_lock_irqsave(&cpg_lock
, flags
);
37 spin_unlock_irqrestore(&cpg_lock
, flags
);
40 static int cpg_simple_notifier_call(struct notifier_block
*nb
,
41 unsigned long action
, void *data
)
43 struct cpg_simple_notifier
*csn
=
44 container_of(nb
, struct cpg_simple_notifier
, nb
);
47 case PM_EVENT_SUSPEND
:
48 csn
->saved
= readl(csn
->reg
);
52 writel(csn
->saved
, csn
->reg
);
58 void cpg_simple_notifier_register(struct raw_notifier_head
*notifiers
,
59 struct cpg_simple_notifier
*csn
)
61 csn
->nb
.notifier_call
= cpg_simple_notifier_call
;
62 raw_notifier_chain_register(notifiers
, &csn
->nb
);
69 #define SDnSRCFC_SHIFT 2
70 #define STPnHCK BIT(9 - SDnSRCFC_SHIFT)
72 static const struct clk_div_table cpg_sdh_div_table
[] = {
74 * These values are recommended by the datasheet. Because they come
75 * first, Linux will only use these.
77 { 0, 1 }, { 1, 2 }, { STPnHCK
| 2, 4 }, { STPnHCK
| 3, 8 },
80 * These values are not recommended because STPnHCK is wrong. But they
81 * have been seen because of broken firmware. So, we support reading
82 * them but Linux will sanitize them when initializing through
85 { STPnHCK
| 0, 1 }, { STPnHCK
| 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 },
90 struct clk
* __init
cpg_sdh_clk_register(const char *name
,
91 void __iomem
*sdnckcr
, const char *parent_name
,
92 struct raw_notifier_head
*notifiers
)
94 struct cpg_simple_notifier
*csn
;
97 csn
= kzalloc(sizeof(*csn
), GFP_KERNEL
);
99 return ERR_PTR(-ENOMEM
);
103 clk
= clk_register_divider_table(NULL
, name
, parent_name
, 0, sdnckcr
,
104 SDnSRCFC_SHIFT
, 8, 0, cpg_sdh_div_table
,
111 cpg_simple_notifier_register(notifiers
, csn
);
115 static const struct clk_div_table cpg_sd_div_table
[] = {
116 { 0, 2 }, { 1, 4 }, { 0, 0 },
119 struct clk
* __init
cpg_sd_clk_register(const char *name
,
120 void __iomem
*sdnckcr
, const char *parent_name
)
122 return clk_register_divider_table(NULL
, name
, parent_name
, 0, sdnckcr
,
123 0, 2, 0, cpg_sd_div_table
, &cpg_lock
);
127 struct clk_divider div
;
128 struct clk_gate gate
;
130 * One notifier covers both RPC and RPCD2 clocks as they are both
131 * controlled by the same RPCCKCR register...
133 struct cpg_simple_notifier csn
;
136 static const struct clk_div_table cpg_rpc_div_table
[] = {
137 { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
140 struct clk
* __init
cpg_rpc_clk_register(const char *name
,
141 void __iomem
*rpcckcr
, const char *parent_name
,
142 struct raw_notifier_head
*notifiers
)
144 struct rpc_clock
*rpc
;
147 rpc
= kzalloc(sizeof(*rpc
), GFP_KERNEL
);
149 return ERR_PTR(-ENOMEM
);
151 rpc
->div
.reg
= rpcckcr
;
153 rpc
->div
.table
= cpg_rpc_div_table
;
154 rpc
->div
.lock
= &cpg_lock
;
156 rpc
->gate
.reg
= rpcckcr
;
157 rpc
->gate
.bit_idx
= 8;
158 rpc
->gate
.flags
= CLK_GATE_SET_TO_DISABLE
;
159 rpc
->gate
.lock
= &cpg_lock
;
161 rpc
->csn
.reg
= rpcckcr
;
163 clk
= clk_register_composite(NULL
, name
, &parent_name
, 1, NULL
, NULL
,
164 &rpc
->div
.hw
, &clk_divider_ops
,
165 &rpc
->gate
.hw
, &clk_gate_ops
,
166 CLK_SET_RATE_PARENT
);
172 cpg_simple_notifier_register(notifiers
, &rpc
->csn
);
177 struct clk_fixed_factor fixed
;
178 struct clk_gate gate
;
181 struct clk
* __init
cpg_rpcd2_clk_register(const char *name
,
182 void __iomem
*rpcckcr
,
183 const char *parent_name
)
185 struct rpcd2_clock
*rpcd2
;
188 rpcd2
= kzalloc(sizeof(*rpcd2
), GFP_KERNEL
);
190 return ERR_PTR(-ENOMEM
);
192 rpcd2
->fixed
.mult
= 1;
193 rpcd2
->fixed
.div
= 2;
195 rpcd2
->gate
.reg
= rpcckcr
;
196 rpcd2
->gate
.bit_idx
= 9;
197 rpcd2
->gate
.flags
= CLK_GATE_SET_TO_DISABLE
;
198 rpcd2
->gate
.lock
= &cpg_lock
;
200 clk
= clk_register_composite(NULL
, name
, &parent_name
, 1, NULL
, NULL
,
201 &rpcd2
->fixed
.hw
, &clk_fixed_factor_ops
,
202 &rpcd2
->gate
.hw
, &clk_gate_ops
,
203 CLK_SET_RATE_PARENT
);