1 // SPDX-License-Identifier: GPL-2.0-only
3 * Toshiba Visconti clock controller
5 * Copyright (c) 2021 TOSHIBA CORPORATION
6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
11 #include <linux/clk-provider.h>
12 #include <linux/delay.h>
13 #include <linux/device.h>
16 #include <linux/of_address.h>
17 #include <linux/regmap.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
23 static inline struct visconti_clk_gate
*to_visconti_clk_gate(struct clk_hw
*hw
)
25 return container_of(hw
, struct visconti_clk_gate
, hw
);
28 static int visconti_gate_clk_is_enabled(struct clk_hw
*hw
)
30 struct visconti_clk_gate
*gate
= to_visconti_clk_gate(hw
);
31 u32 clk
= BIT(gate
->ck_idx
);
34 regmap_read(gate
->regmap
, gate
->ckon_offset
, &val
);
35 return (val
& clk
) ? 1 : 0;
38 static void visconti_gate_clk_disable(struct clk_hw
*hw
)
40 struct visconti_clk_gate
*gate
= to_visconti_clk_gate(hw
);
41 u32 clk
= BIT(gate
->ck_idx
);
44 spin_lock_irqsave(gate
->lock
, flags
);
46 if (!visconti_gate_clk_is_enabled(hw
)) {
47 spin_unlock_irqrestore(gate
->lock
, flags
);
51 regmap_update_bits(gate
->regmap
, gate
->ckoff_offset
, clk
, clk
);
52 spin_unlock_irqrestore(gate
->lock
, flags
);
55 static int visconti_gate_clk_enable(struct clk_hw
*hw
)
57 struct visconti_clk_gate
*gate
= to_visconti_clk_gate(hw
);
58 u32 clk
= BIT(gate
->ck_idx
);
61 spin_lock_irqsave(gate
->lock
, flags
);
62 regmap_update_bits(gate
->regmap
, gate
->ckon_offset
, clk
, clk
);
63 spin_unlock_irqrestore(gate
->lock
, flags
);
68 static const struct clk_ops visconti_clk_gate_ops
= {
69 .enable
= visconti_gate_clk_enable
,
70 .disable
= visconti_gate_clk_disable
,
71 .is_enabled
= visconti_gate_clk_is_enabled
,
74 static struct clk_hw
*visconti_clk_register_gate(struct device
*dev
,
76 const char *parent_name
,
77 struct regmap
*regmap
,
78 const struct visconti_clk_gate_table
*clks
,
84 struct visconti_clk_gate
*gate
;
85 struct clk_parent_data
*pdata
;
86 struct clk_init_data init
;
90 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
92 return ERR_PTR(-ENOMEM
);
94 pdata
->name
= pdata
->fw_name
= parent_name
;
96 gate
= devm_kzalloc(dev
, sizeof(*gate
), GFP_KERNEL
);
98 return ERR_PTR(-ENOMEM
);
101 init
.ops
= &visconti_clk_gate_ops
;
102 init
.flags
= clks
->flags
;
103 init
.parent_data
= pdata
;
104 init
.num_parents
= 1;
106 gate
->regmap
= regmap
;
107 gate
->ckon_offset
= clks
->ckon_offset
;
108 gate
->ckoff_offset
= clks
->ckoff_offset
;
109 gate
->ck_idx
= clks
->ck_idx
;
110 gate
->rson_offset
= rson_offset
;
111 gate
->rsoff_offset
= rsoff_offset
;
112 gate
->rs_idx
= rs_idx
;
114 gate
->hw
.init
= &init
;
117 ret
= devm_clk_hw_register(dev
, hw
);
124 int visconti_clk_register_gates(struct visconti_clk_provider
*ctx
,
125 const struct visconti_clk_gate_table
*clks
,
127 const struct visconti_reset_data
*reset
,
130 struct device
*dev
= ctx
->dev
;
133 for (i
= 0; i
< num_gate
; i
++) {
134 const char *parent_div_name
= clks
[i
].parent_data
[0].name
;
135 struct clk_parent_data
*pdata
;
136 u32 rson_offset
, rsoff_offset
;
137 struct clk_hw
*gate_clk
;
138 struct clk_hw
*div_clk
;
142 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
146 dev_name
= devm_kasprintf(dev
, GFP_KERNEL
, "%s_div", clks
[i
].name
);
150 if (clks
[i
].rs_id
!= NO_RESET
) {
151 rson_offset
= reset
[clks
[i
].rs_id
].rson_offset
;
152 rsoff_offset
= reset
[clks
[i
].rs_id
].rsoff_offset
;
153 rs_idx
= reset
[clks
[i
].rs_id
].rs_idx
;
155 rson_offset
= rsoff_offset
= rs_idx
= -1;
158 div_clk
= devm_clk_hw_register_fixed_factor(dev
,
164 return PTR_ERR(div_clk
);
166 gate_clk
= visconti_clk_register_gate(dev
,
175 if (IS_ERR(gate_clk
)) {
176 dev_err(dev
, "%s: failed to register clock %s\n",
177 __func__
, clks
[i
].name
);
178 return PTR_ERR(gate_clk
);
181 ctx
->clk_data
.hws
[clks
[i
].id
] = gate_clk
;
187 struct visconti_clk_provider
*visconti_init_clk(struct device
*dev
,
188 struct regmap
*regmap
,
189 unsigned long nr_clks
)
191 struct visconti_clk_provider
*ctx
;
194 ctx
= devm_kzalloc(dev
, struct_size(ctx
, clk_data
.hws
, nr_clks
), GFP_KERNEL
);
196 return ERR_PTR(-ENOMEM
);
198 for (i
= 0; i
< nr_clks
; ++i
)
199 ctx
->clk_data
.hws
[i
] = ERR_PTR(-ENOENT
);
200 ctx
->clk_data
.num
= nr_clks
;
203 ctx
->regmap
= regmap
;