xref: /linux/drivers/clk/socfpga/clk-pll-s10.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
107afb8dbSDinh Nguyen // SPDX-License-Identifier: GPL-2.0
207afb8dbSDinh Nguyen /*
307afb8dbSDinh Nguyen  * Copyright (C) 2017, Intel Corporation
407afb8dbSDinh Nguyen  */
507afb8dbSDinh Nguyen #include <linux/slab.h>
607afb8dbSDinh Nguyen #include <linux/clk-provider.h>
762e59c4eSStephen Boyd #include <linux/io.h>
807afb8dbSDinh Nguyen 
907afb8dbSDinh Nguyen #include "stratix10-clk.h"
1007afb8dbSDinh Nguyen #include "clk.h"
1107afb8dbSDinh Nguyen 
1207afb8dbSDinh Nguyen /* Clock Manager offsets */
1307afb8dbSDinh Nguyen #define CLK_MGR_PLL_CLK_SRC_SHIFT	16
1407afb8dbSDinh Nguyen #define CLK_MGR_PLL_CLK_SRC_MASK	0x3
1507afb8dbSDinh Nguyen 
1607afb8dbSDinh Nguyen /* PLL Clock enable bits */
1707afb8dbSDinh Nguyen #define SOCFPGA_PLL_POWER		0
1807afb8dbSDinh Nguyen #define SOCFPGA_PLL_RESET_MASK		0x2
1907afb8dbSDinh Nguyen #define SOCFPGA_PLL_REFDIV_MASK		0x00003F00
2007afb8dbSDinh Nguyen #define SOCFPGA_PLL_REFDIV_SHIFT	8
2180c6b7a0SDinh Nguyen #define SOCFPGA_PLL_AREFDIV_MASK	0x00000F00
2280c6b7a0SDinh Nguyen #define SOCFPGA_PLL_DREFDIV_MASK	0x00003000
2380c6b7a0SDinh Nguyen #define SOCFPGA_PLL_DREFDIV_SHIFT	12
2407afb8dbSDinh Nguyen #define SOCFPGA_PLL_MDIV_MASK		0xFF000000
2507afb8dbSDinh Nguyen #define SOCFPGA_PLL_MDIV_SHIFT		24
2680c6b7a0SDinh Nguyen #define SOCFPGA_AGILEX_PLL_MDIV_MASK	0x000003FF
2707afb8dbSDinh Nguyen #define SWCTRLBTCLKSEL_MASK		0x200
2807afb8dbSDinh Nguyen #define SWCTRLBTCLKSEL_SHIFT		9
2907afb8dbSDinh Nguyen 
30a0f9819cSDinh Nguyen #define SOCFPGA_N5X_PLLDIV_FDIV_MASK	GENMASK(16, 8)
31a0f9819cSDinh Nguyen #define SOCFPGA_N5X_PLLDIV_FDIV_SHIFT	8
32a0f9819cSDinh Nguyen #define SOCFPGA_N5X_PLLDIV_RDIV_MASK	GENMASK(5, 0)
33a0f9819cSDinh Nguyen #define SOCFPGA_N5X_PLLDIV_QDIV_MASK	GENMASK(26, 24)
34a0f9819cSDinh Nguyen #define SOCFPGA_N5X_PLLDIV_QDIV_SHIFT	24
35a0f9819cSDinh Nguyen 
3607afb8dbSDinh Nguyen #define SOCFPGA_BOOT_CLK		"boot_clk"
3707afb8dbSDinh Nguyen 
3807afb8dbSDinh Nguyen #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
3907afb8dbSDinh Nguyen 
n5x_clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)40a0f9819cSDinh Nguyen static unsigned long n5x_clk_pll_recalc_rate(struct clk_hw *hwclk,
41a0f9819cSDinh Nguyen 						unsigned long parent_rate)
42a0f9819cSDinh Nguyen {
43a0f9819cSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
44a0f9819cSDinh Nguyen 	unsigned long fdiv, reg, rdiv, qdiv;
45a0f9819cSDinh Nguyen 	u32 power = 1;
46a0f9819cSDinh Nguyen 
47a0f9819cSDinh Nguyen 	/* read VCO1 reg for numerator and denominator */
48a0f9819cSDinh Nguyen 	reg = readl(socfpgaclk->hw.reg + 0x8);
49a0f9819cSDinh Nguyen 	fdiv = (reg & SOCFPGA_N5X_PLLDIV_FDIV_MASK) >> SOCFPGA_N5X_PLLDIV_FDIV_SHIFT;
50a0f9819cSDinh Nguyen 	rdiv = (reg & SOCFPGA_N5X_PLLDIV_RDIV_MASK);
51a0f9819cSDinh Nguyen 	qdiv = (reg & SOCFPGA_N5X_PLLDIV_QDIV_MASK) >> SOCFPGA_N5X_PLLDIV_QDIV_SHIFT;
52a0f9819cSDinh Nguyen 
53a0f9819cSDinh Nguyen 	while (qdiv) {
54a0f9819cSDinh Nguyen 		power *= 2;
55a0f9819cSDinh Nguyen 		qdiv--;
56a0f9819cSDinh Nguyen 	}
57a0f9819cSDinh Nguyen 
58a0f9819cSDinh Nguyen 	return ((parent_rate * 2 * (fdiv + 1)) / ((rdiv + 1) * power));
59a0f9819cSDinh Nguyen }
60a0f9819cSDinh Nguyen 
agilex_clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)6180c6b7a0SDinh Nguyen static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
6280c6b7a0SDinh Nguyen 						unsigned long parent_rate)
6380c6b7a0SDinh Nguyen {
6480c6b7a0SDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
6580c6b7a0SDinh Nguyen 	unsigned long arefdiv, reg, mdiv;
6680c6b7a0SDinh Nguyen 	unsigned long long vco_freq;
6780c6b7a0SDinh Nguyen 
6880c6b7a0SDinh Nguyen 	/* read VCO1 reg for numerator and denominator */
6980c6b7a0SDinh Nguyen 	reg = readl(socfpgaclk->hw.reg);
7080c6b7a0SDinh Nguyen 	arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
7180c6b7a0SDinh Nguyen 
7280c6b7a0SDinh Nguyen 	vco_freq = (unsigned long long)parent_rate / arefdiv;
7380c6b7a0SDinh Nguyen 
7480c6b7a0SDinh Nguyen 	/* Read mdiv and fdiv from the fdbck register */
7580c6b7a0SDinh Nguyen 	reg = readl(socfpgaclk->hw.reg + 0x24);
7680c6b7a0SDinh Nguyen 	mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
7780c6b7a0SDinh Nguyen 
7880c6b7a0SDinh Nguyen 	vco_freq = (unsigned long long)vco_freq * mdiv;
7980c6b7a0SDinh Nguyen 	return (unsigned long)vco_freq;
8080c6b7a0SDinh Nguyen }
8180c6b7a0SDinh Nguyen 
clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)8207afb8dbSDinh Nguyen static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
8307afb8dbSDinh Nguyen 					 unsigned long parent_rate)
8407afb8dbSDinh Nguyen {
8507afb8dbSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
86*0248bfb2SThorsten Blum 	u32 mdiv;
87*0248bfb2SThorsten Blum 	u32 refdiv;
88*0248bfb2SThorsten Blum 	u32 reg;
8907afb8dbSDinh Nguyen 	unsigned long long vco_freq;
9007afb8dbSDinh Nguyen 
9107afb8dbSDinh Nguyen 	/* read VCO1 reg for numerator and denominator */
9207afb8dbSDinh Nguyen 	reg = readl(socfpgaclk->hw.reg);
9307afb8dbSDinh Nguyen 	refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
94cc26ed7bSDinh Nguyen 
95cc26ed7bSDinh Nguyen 	vco_freq = parent_rate;
96cc26ed7bSDinh Nguyen 	do_div(vco_freq, refdiv);
9707afb8dbSDinh Nguyen 
9807afb8dbSDinh Nguyen 	/* Read mdiv and fdiv from the fdbck register */
9907afb8dbSDinh Nguyen 	reg = readl(socfpgaclk->hw.reg + 0x4);
10007afb8dbSDinh Nguyen 	mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT;
101c0a636e4SDinh Nguyen 	vco_freq = (unsigned long long)vco_freq * (mdiv + 6);
10207afb8dbSDinh Nguyen 
10307afb8dbSDinh Nguyen 	return (unsigned long)vco_freq;
10407afb8dbSDinh Nguyen }
10507afb8dbSDinh Nguyen 
clk_boot_clk_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)10607afb8dbSDinh Nguyen static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
10707afb8dbSDinh Nguyen 					 unsigned long parent_rate)
10807afb8dbSDinh Nguyen {
10907afb8dbSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
11052d1a8daSColin Ian King 	u32 div;
11107afb8dbSDinh Nguyen 
11207afb8dbSDinh Nguyen 	div = ((readl(socfpgaclk->hw.reg) &
11307afb8dbSDinh Nguyen 		SWCTRLBTCLKSEL_MASK) >>
11407afb8dbSDinh Nguyen 		SWCTRLBTCLKSEL_SHIFT);
11507afb8dbSDinh Nguyen 	div += 1;
11608d92c7aSColin Ian King 	return parent_rate / div;
11707afb8dbSDinh Nguyen }
11807afb8dbSDinh Nguyen 
11907afb8dbSDinh Nguyen 
clk_pll_get_parent(struct clk_hw * hwclk)12007afb8dbSDinh Nguyen static u8 clk_pll_get_parent(struct clk_hw *hwclk)
12107afb8dbSDinh Nguyen {
12207afb8dbSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
12307afb8dbSDinh Nguyen 	u32 pll_src;
12407afb8dbSDinh Nguyen 
12507afb8dbSDinh Nguyen 	pll_src = readl(socfpgaclk->hw.reg);
12607afb8dbSDinh Nguyen 	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
12707afb8dbSDinh Nguyen 		CLK_MGR_PLL_CLK_SRC_MASK;
12807afb8dbSDinh Nguyen }
12907afb8dbSDinh Nguyen 
clk_boot_get_parent(struct clk_hw * hwclk)13007afb8dbSDinh Nguyen static u8 clk_boot_get_parent(struct clk_hw *hwclk)
13107afb8dbSDinh Nguyen {
13207afb8dbSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
13307afb8dbSDinh Nguyen 	u32 pll_src;
13407afb8dbSDinh Nguyen 
13507afb8dbSDinh Nguyen 	pll_src = readl(socfpgaclk->hw.reg);
13607afb8dbSDinh Nguyen 	return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
13707afb8dbSDinh Nguyen 		SWCTRLBTCLKSEL_MASK;
13807afb8dbSDinh Nguyen }
13907afb8dbSDinh Nguyen 
clk_pll_prepare(struct clk_hw * hwclk)14007afb8dbSDinh Nguyen static int clk_pll_prepare(struct clk_hw *hwclk)
14107afb8dbSDinh Nguyen {
14207afb8dbSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
14307afb8dbSDinh Nguyen 	u32 reg;
14407afb8dbSDinh Nguyen 
14507afb8dbSDinh Nguyen 	/* Bring PLL out of reset */
14607afb8dbSDinh Nguyen 	reg = readl(socfpgaclk->hw.reg);
14707afb8dbSDinh Nguyen 	reg |= SOCFPGA_PLL_RESET_MASK;
14807afb8dbSDinh Nguyen 	writel(reg, socfpgaclk->hw.reg);
14907afb8dbSDinh Nguyen 
15007afb8dbSDinh Nguyen 	return 0;
15107afb8dbSDinh Nguyen }
15207afb8dbSDinh Nguyen 
n5x_clk_pll_prepare(struct clk_hw * hwclk)153a0f9819cSDinh Nguyen static int n5x_clk_pll_prepare(struct clk_hw *hwclk)
154a0f9819cSDinh Nguyen {
155a0f9819cSDinh Nguyen 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
156a0f9819cSDinh Nguyen 	u32 reg;
157a0f9819cSDinh Nguyen 
158a0f9819cSDinh Nguyen 	/* Bring PLL out of reset */
159a0f9819cSDinh Nguyen 	reg = readl(socfpgaclk->hw.reg + 0x4);
160a0f9819cSDinh Nguyen 	reg |= SOCFPGA_PLL_RESET_MASK;
161a0f9819cSDinh Nguyen 	writel(reg, socfpgaclk->hw.reg + 0x4);
162a0f9819cSDinh Nguyen 
163a0f9819cSDinh Nguyen 	return 0;
164a0f9819cSDinh Nguyen }
165a0f9819cSDinh Nguyen 
166a0f9819cSDinh Nguyen static const struct clk_ops n5x_clk_pll_ops = {
167a0f9819cSDinh Nguyen 	.recalc_rate = n5x_clk_pll_recalc_rate,
168a0f9819cSDinh Nguyen 	.get_parent = clk_pll_get_parent,
169a0f9819cSDinh Nguyen 	.prepare = n5x_clk_pll_prepare,
170a0f9819cSDinh Nguyen };
171a0f9819cSDinh Nguyen 
17280c6b7a0SDinh Nguyen static const struct clk_ops agilex_clk_pll_ops = {
17380c6b7a0SDinh Nguyen 	.recalc_rate = agilex_clk_pll_recalc_rate,
17480c6b7a0SDinh Nguyen 	.get_parent = clk_pll_get_parent,
17580c6b7a0SDinh Nguyen 	.prepare = clk_pll_prepare,
17680c6b7a0SDinh Nguyen };
17780c6b7a0SDinh Nguyen 
178d52579ceSDinh Nguyen static const struct clk_ops clk_pll_ops = {
17907afb8dbSDinh Nguyen 	.recalc_rate = clk_pll_recalc_rate,
18007afb8dbSDinh Nguyen 	.get_parent = clk_pll_get_parent,
18107afb8dbSDinh Nguyen 	.prepare = clk_pll_prepare,
18207afb8dbSDinh Nguyen };
18307afb8dbSDinh Nguyen 
184d52579ceSDinh Nguyen static const struct clk_ops clk_boot_ops = {
18507afb8dbSDinh Nguyen 	.recalc_rate = clk_boot_clk_recalc_rate,
18607afb8dbSDinh Nguyen 	.get_parent = clk_boot_get_parent,
18707afb8dbSDinh Nguyen 	.prepare = clk_pll_prepare,
18807afb8dbSDinh Nguyen };
18907afb8dbSDinh Nguyen 
s10_register_pll(const struct stratix10_pll_clock * clks,void __iomem * reg)190ba7e2584SDinh Nguyen struct clk_hw *s10_register_pll(const struct stratix10_pll_clock *clks,
1918c0e783dSDinh Nguyen 			     void __iomem *reg)
19207afb8dbSDinh Nguyen {
193ba7e2584SDinh Nguyen 	struct clk_hw *hw_clk;
19407afb8dbSDinh Nguyen 	struct socfpga_pll *pll_clk;
19507afb8dbSDinh Nguyen 	struct clk_init_data init;
1968c0e783dSDinh Nguyen 	const char *name = clks->name;
197ba7e2584SDinh Nguyen 	int ret;
19807afb8dbSDinh Nguyen 
19907afb8dbSDinh Nguyen 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
20007afb8dbSDinh Nguyen 	if (WARN_ON(!pll_clk))
20107afb8dbSDinh Nguyen 		return NULL;
20207afb8dbSDinh Nguyen 
2038c0e783dSDinh Nguyen 	pll_clk->hw.reg = reg + clks->offset;
20407afb8dbSDinh Nguyen 
20507afb8dbSDinh Nguyen 	if (streq(name, SOCFPGA_BOOT_CLK))
20607afb8dbSDinh Nguyen 		init.ops = &clk_boot_ops;
20707afb8dbSDinh Nguyen 	else
20807afb8dbSDinh Nguyen 		init.ops = &clk_pll_ops;
20907afb8dbSDinh Nguyen 
21007afb8dbSDinh Nguyen 	init.name = name;
2118c0e783dSDinh Nguyen 	init.flags = clks->flags;
21207afb8dbSDinh Nguyen 
2138c0e783dSDinh Nguyen 	init.num_parents = clks->num_parents;
214762d961aSDinh Nguyen 	init.parent_names = NULL;
215762d961aSDinh Nguyen 	init.parent_data = clks->parent_data;
21607afb8dbSDinh Nguyen 	pll_clk->hw.hw.init = &init;
21707afb8dbSDinh Nguyen 
21807afb8dbSDinh Nguyen 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
21907afb8dbSDinh Nguyen 
220ba7e2584SDinh Nguyen 	hw_clk = &pll_clk->hw.hw;
221ba7e2584SDinh Nguyen 
222ba7e2584SDinh Nguyen 	ret = clk_hw_register(NULL, hw_clk);
223ba7e2584SDinh Nguyen 	if (ret) {
22407afb8dbSDinh Nguyen 		kfree(pll_clk);
225ba7e2584SDinh Nguyen 		return ERR_PTR(ret);
22607afb8dbSDinh Nguyen 	}
227ba7e2584SDinh Nguyen 	return hw_clk;
22807afb8dbSDinh Nguyen }
22980c6b7a0SDinh Nguyen 
agilex_register_pll(const struct stratix10_pll_clock * clks,void __iomem * reg)230ba7e2584SDinh Nguyen struct clk_hw *agilex_register_pll(const struct stratix10_pll_clock *clks,
23180c6b7a0SDinh Nguyen 				void __iomem *reg)
23280c6b7a0SDinh Nguyen {
233ba7e2584SDinh Nguyen 	struct clk_hw *hw_clk;
23480c6b7a0SDinh Nguyen 	struct socfpga_pll *pll_clk;
23580c6b7a0SDinh Nguyen 	struct clk_init_data init;
23680c6b7a0SDinh Nguyen 	const char *name = clks->name;
237ba7e2584SDinh Nguyen 	int ret;
23880c6b7a0SDinh Nguyen 
23980c6b7a0SDinh Nguyen 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
24080c6b7a0SDinh Nguyen 	if (WARN_ON(!pll_clk))
24180c6b7a0SDinh Nguyen 		return NULL;
24280c6b7a0SDinh Nguyen 
24380c6b7a0SDinh Nguyen 	pll_clk->hw.reg = reg + clks->offset;
24480c6b7a0SDinh Nguyen 
24580c6b7a0SDinh Nguyen 	if (streq(name, SOCFPGA_BOOT_CLK))
24680c6b7a0SDinh Nguyen 		init.ops = &clk_boot_ops;
24780c6b7a0SDinh Nguyen 	else
24880c6b7a0SDinh Nguyen 		init.ops = &agilex_clk_pll_ops;
24980c6b7a0SDinh Nguyen 
25080c6b7a0SDinh Nguyen 	init.name = name;
25180c6b7a0SDinh Nguyen 	init.flags = clks->flags;
25280c6b7a0SDinh Nguyen 
25380c6b7a0SDinh Nguyen 	init.num_parents = clks->num_parents;
25480c6b7a0SDinh Nguyen 	init.parent_names = NULL;
25580c6b7a0SDinh Nguyen 	init.parent_data = clks->parent_data;
25680c6b7a0SDinh Nguyen 	pll_clk->hw.hw.init = &init;
25780c6b7a0SDinh Nguyen 
25880c6b7a0SDinh Nguyen 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
259ba7e2584SDinh Nguyen 	hw_clk = &pll_clk->hw.hw;
26080c6b7a0SDinh Nguyen 
261ba7e2584SDinh Nguyen 	ret = clk_hw_register(NULL, hw_clk);
262ba7e2584SDinh Nguyen 	if (ret) {
26380c6b7a0SDinh Nguyen 		kfree(pll_clk);
264ba7e2584SDinh Nguyen 		return ERR_PTR(ret);
26580c6b7a0SDinh Nguyen 	}
266ba7e2584SDinh Nguyen 	return hw_clk;
26780c6b7a0SDinh Nguyen }
268a0f9819cSDinh Nguyen 
n5x_register_pll(const struct stratix10_pll_clock * clks,void __iomem * reg)269ba7e2584SDinh Nguyen struct clk_hw *n5x_register_pll(const struct stratix10_pll_clock *clks,
270a0f9819cSDinh Nguyen 			     void __iomem *reg)
271a0f9819cSDinh Nguyen {
272ba7e2584SDinh Nguyen 	struct clk_hw *hw_clk;
273a0f9819cSDinh Nguyen 	struct socfpga_pll *pll_clk;
274a0f9819cSDinh Nguyen 	struct clk_init_data init;
275a0f9819cSDinh Nguyen 	const char *name = clks->name;
276ba7e2584SDinh Nguyen 	int ret;
277a0f9819cSDinh Nguyen 
278a0f9819cSDinh Nguyen 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
279a0f9819cSDinh Nguyen 	if (WARN_ON(!pll_clk))
280a0f9819cSDinh Nguyen 		return NULL;
281a0f9819cSDinh Nguyen 
282a0f9819cSDinh Nguyen 	pll_clk->hw.reg = reg + clks->offset;
283a0f9819cSDinh Nguyen 
284a0f9819cSDinh Nguyen 	if (streq(name, SOCFPGA_BOOT_CLK))
285a0f9819cSDinh Nguyen 		init.ops = &clk_boot_ops;
286a0f9819cSDinh Nguyen 	else
287a0f9819cSDinh Nguyen 		init.ops = &n5x_clk_pll_ops;
288a0f9819cSDinh Nguyen 
289a0f9819cSDinh Nguyen 	init.name = name;
290a0f9819cSDinh Nguyen 	init.flags = clks->flags;
291a0f9819cSDinh Nguyen 
292a0f9819cSDinh Nguyen 	init.num_parents = clks->num_parents;
293a0f9819cSDinh Nguyen 	init.parent_names = NULL;
294a0f9819cSDinh Nguyen 	init.parent_data = clks->parent_data;
295a0f9819cSDinh Nguyen 	pll_clk->hw.hw.init = &init;
296a0f9819cSDinh Nguyen 
297a0f9819cSDinh Nguyen 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
298ba7e2584SDinh Nguyen 	hw_clk = &pll_clk->hw.hw;
299a0f9819cSDinh Nguyen 
300ba7e2584SDinh Nguyen 	ret = clk_hw_register(NULL, hw_clk);
301ba7e2584SDinh Nguyen 	if (ret) {
302a0f9819cSDinh Nguyen 		kfree(pll_clk);
303ba7e2584SDinh Nguyen 		return ERR_PTR(ret);
304a0f9819cSDinh Nguyen 	}
305ba7e2584SDinh Nguyen 	return hw_clk;
306a0f9819cSDinh Nguyen }
307