1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Microchip LAN966x SoC Clock driver.
5 * Copyright (C) 2021 Microchip Technology, Inc. and its subsidiaries
7 * Author: Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
10 #include <linux/bitfield.h>
11 #include <linux/clk-provider.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
19 #include <dt-bindings/clock/microchip,lan966x.h>
21 #define GCK_ENA BIT(0)
22 #define GCK_SRC_SEL GENMASK(9, 8)
23 #define GCK_PRESCALER GENMASK(23, 16)
27 static const char * const lan966x_clk_names
[] = {
28 "qspi0", "qspi1", "qspi2", "sdmmc0",
29 "pi", "mcan0", "mcan1", "flexcom0",
30 "flexcom1", "flexcom2", "flexcom3",
31 "flexcom4", "timer1", "usb_refclk",
34 static const char * const lan969x_clk_names
[] = {
35 "qspi0", "qspi2", "sdmmc0", "sdmmc1",
36 "mcan0", "mcan1", "flexcom0",
37 "flexcom1", "flexcom2", "flexcom3",
38 "timer1", "usb_refclk",
45 #define to_lan966x_gck(hw) container_of(hw, struct lan966x_gck, hw)
47 static const struct clk_parent_data lan966x_gck_pdata
[] = {
48 { .fw_name
= "cpu", },
49 { .fw_name
= "ddr", },
50 { .fw_name
= "sys", },
53 static struct clk_init_data init
= {
54 .parent_data
= lan966x_gck_pdata
,
55 .num_parents
= ARRAY_SIZE(lan966x_gck_pdata
),
58 struct clk_gate_soc_desc
{
63 static const struct clk_gate_soc_desc lan966x_clk_gate_desc
[] = {
71 static const struct clk_gate_soc_desc lan969x_clk_gate_desc
[] = {
78 struct lan966x_match_data
{
80 const char * const *clk_name
;
81 const struct clk_gate_soc_desc
*clk_gate_desc
;
86 static struct lan966x_match_data lan966x_desc
= {
88 .clk_name
= lan966x_clk_names
,
89 .clk_gate_desc
= lan966x_clk_gate_desc
,
91 .num_generic_clks
= 14,
94 static struct lan966x_match_data lan969x_desc
= {
96 .clk_name
= lan969x_clk_names
,
97 .clk_gate_desc
= lan969x_clk_gate_desc
,
99 .num_generic_clks
= 12,
102 static DEFINE_SPINLOCK(clk_gate_lock
);
103 static void __iomem
*base
;
105 static int lan966x_gck_enable(struct clk_hw
*hw
)
107 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
108 u32 val
= readl(gck
->reg
);
111 writel(val
, gck
->reg
);
116 static void lan966x_gck_disable(struct clk_hw
*hw
)
118 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
119 u32 val
= readl(gck
->reg
);
122 writel(val
, gck
->reg
);
125 static int lan966x_gck_set_rate(struct clk_hw
*hw
,
127 unsigned long parent_rate
)
129 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
130 u32 div
, val
= readl(gck
->reg
);
132 if (rate
== 0 || parent_rate
== 0)
136 div
= parent_rate
/ rate
;
137 val
&= ~GCK_PRESCALER
;
138 val
|= FIELD_PREP(GCK_PRESCALER
, (div
- 1));
139 writel(val
, gck
->reg
);
144 static unsigned long lan966x_gck_recalc_rate(struct clk_hw
*hw
,
145 unsigned long parent_rate
)
147 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
148 u32 div
, val
= readl(gck
->reg
);
150 div
= FIELD_GET(GCK_PRESCALER
, val
);
152 return parent_rate
/ (div
+ 1);
155 static int lan966x_gck_determine_rate(struct clk_hw
*hw
,
156 struct clk_rate_request
*req
)
158 struct clk_hw
*parent
;
161 for (i
= 0; i
< clk_hw_get_num_parents(hw
); ++i
) {
162 parent
= clk_hw_get_parent_by_index(hw
, i
);
166 /* Allowed prescaler divider range is 0-255 */
167 if (clk_hw_get_rate(parent
) / req
->rate
<= DIV_MAX
) {
168 req
->best_parent_hw
= parent
;
169 req
->best_parent_rate
= clk_hw_get_rate(parent
);
178 static u8
lan966x_gck_get_parent(struct clk_hw
*hw
)
180 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
181 u32 val
= readl(gck
->reg
);
183 return FIELD_GET(GCK_SRC_SEL
, val
);
186 static int lan966x_gck_set_parent(struct clk_hw
*hw
, u8 index
)
188 struct lan966x_gck
*gck
= to_lan966x_gck(hw
);
189 u32 val
= readl(gck
->reg
);
192 val
|= FIELD_PREP(GCK_SRC_SEL
, index
);
193 writel(val
, gck
->reg
);
198 static const struct clk_ops lan966x_gck_ops
= {
199 .enable
= lan966x_gck_enable
,
200 .disable
= lan966x_gck_disable
,
201 .set_rate
= lan966x_gck_set_rate
,
202 .recalc_rate
= lan966x_gck_recalc_rate
,
203 .determine_rate
= lan966x_gck_determine_rate
,
204 .set_parent
= lan966x_gck_set_parent
,
205 .get_parent
= lan966x_gck_get_parent
,
208 static struct clk_hw
*lan966x_gck_clk_register(struct device
*dev
, int i
)
210 struct lan966x_gck
*priv
;
213 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
215 return ERR_PTR(-ENOMEM
);
217 priv
->reg
= base
+ (i
* 4);
218 priv
->hw
.init
= &init
;
219 ret
= devm_clk_hw_register(dev
, &priv
->hw
);
226 static int lan966x_gate_clk_register(struct device
*dev
,
227 const struct lan966x_match_data
*data
,
228 struct clk_hw_onecell_data
*hw_data
,
229 void __iomem
*gate_base
)
231 for (int i
= data
->num_generic_clks
; i
< data
->num_total_clks
; ++i
) {
232 int idx
= i
- data
->num_generic_clks
;
233 const struct clk_gate_soc_desc
*desc
;
235 desc
= &data
->clk_gate_desc
[idx
];
238 devm_clk_hw_register_gate(dev
, desc
->name
,
239 data
->name
, 0, gate_base
,
243 if (IS_ERR(hw_data
->hws
[i
]))
244 return dev_err_probe(dev
, PTR_ERR(hw_data
->hws
[i
]),
245 "failed to register %s clock\n",
252 static int lan966x_clk_probe(struct platform_device
*pdev
)
254 const struct lan966x_match_data
*data
;
255 struct clk_hw_onecell_data
*hw_data
;
256 struct device
*dev
= &pdev
->dev
;
257 void __iomem
*gate_base
;
258 struct resource
*res
;
261 data
= device_get_match_data(dev
);
265 hw_data
= devm_kzalloc(dev
, struct_size(hw_data
, hws
, data
->num_total_clks
),
270 base
= devm_platform_ioremap_resource(pdev
, 0);
272 return PTR_ERR(base
);
274 init
.ops
= &lan966x_gck_ops
;
276 hw_data
->num
= data
->num_generic_clks
;
278 for (i
= 0; i
< data
->num_generic_clks
; i
++) {
279 init
.name
= data
->clk_name
[i
];
280 hw_data
->hws
[i
] = lan966x_gck_clk_register(dev
, i
);
281 if (IS_ERR(hw_data
->hws
[i
])) {
282 dev_err(dev
, "failed to register %s clock\n",
284 return PTR_ERR(hw_data
->hws
[i
]);
288 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
290 gate_base
= devm_ioremap_resource(&pdev
->dev
, res
);
291 if (IS_ERR(gate_base
))
292 return PTR_ERR(gate_base
);
294 hw_data
->num
= data
->num_total_clks
;
296 ret
= lan966x_gate_clk_register(dev
, data
, hw_data
, gate_base
);
301 return devm_of_clk_add_hw_provider(dev
, of_clk_hw_onecell_get
, hw_data
);
304 static const struct of_device_id lan966x_clk_dt_ids
[] = {
305 { .compatible
= "microchip,lan966x-gck", .data
= &lan966x_desc
},
306 { .compatible
= "microchip,lan9691-gck", .data
= &lan969x_desc
},
309 MODULE_DEVICE_TABLE(of
, lan966x_clk_dt_ids
);
311 static struct platform_driver lan966x_clk_driver
= {
312 .probe
= lan966x_clk_probe
,
314 .name
= "lan966x-clk",
315 .of_match_table
= lan966x_clk_dt_ids
,
318 module_platform_driver(lan966x_clk_driver
);
320 MODULE_AUTHOR("Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>");
321 MODULE_DESCRIPTION("LAN966X clock driver");
322 MODULE_LICENSE("GPL v2");