brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · f5c1ca4 Raw
217 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2017, Intel Corporation4 */5#include <linux/slab.h>6#include <linux/clk-provider.h>7#include <linux/io.h>8 9#include "stratix10-clk.h"10#include "clk.h"11 12#define CLK_MGR_FREE_SHIFT		1613#define CLK_MGR_FREE_MASK		0x714#define SWCTRLBTCLKSEN_SHIFT		815 16#define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)17 18static unsigned long n5x_clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,19					     unsigned long parent_rate)20{21	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);22	unsigned long div;23	unsigned long shift = socfpgaclk->shift;24	u32 val;25 26	val = readl(socfpgaclk->hw.reg);27	val &= (0x1f << shift);28	div = (val >> shift) + 1;29 30	return parent_rate / div;31}32 33static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,34					     unsigned long parent_rate)35{36	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);37	unsigned long div = 1;38	u32 val;39 40	val = readl(socfpgaclk->hw.reg);41	val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);42	parent_rate /= val;43 44	return parent_rate / div;45}46 47static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,48					     unsigned long parent_rate)49{50	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);51	unsigned long div = 1;52 53	if (socfpgaclk->fixed_div) {54		div = socfpgaclk->fixed_div;55	} else {56		if (socfpgaclk->hw.reg)57			div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);58	}59 60	return parent_rate / div;61}62 63static u8 clk_periclk_get_parent(struct clk_hw *hwclk)64{65	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);66	u32 clk_src, mask;67	u8 parent = 0;68 69	/* handle the bypass first */70	if (socfpgaclk->bypass_reg) {71		mask = (0x1 << socfpgaclk->bypass_shift);72		parent = ((readl(socfpgaclk->bypass_reg) & mask) >>73			   socfpgaclk->bypass_shift);74		if (parent)75			return parent;76	}77 78	if (socfpgaclk->hw.reg) {79		clk_src = readl(socfpgaclk->hw.reg);80		parent = (clk_src >> CLK_MGR_FREE_SHIFT) &81			  CLK_MGR_FREE_MASK;82	}83	return parent;84}85 86static const struct clk_ops n5x_peri_c_clk_ops = {87	.recalc_rate = n5x_clk_peri_c_clk_recalc_rate,88	.get_parent = clk_periclk_get_parent,89};90 91static const struct clk_ops peri_c_clk_ops = {92	.recalc_rate = clk_peri_c_clk_recalc_rate,93	.get_parent = clk_periclk_get_parent,94};95 96static const struct clk_ops peri_cnt_clk_ops = {97	.recalc_rate = clk_peri_cnt_clk_recalc_rate,98	.get_parent = clk_periclk_get_parent,99};100 101struct clk_hw *s10_register_periph(const struct stratix10_perip_c_clock *clks,102				void __iomem *reg)103{104	struct clk_hw *hw_clk;105	struct socfpga_periph_clk *periph_clk;106	struct clk_init_data init;107	const char *name = clks->name;108	const char *parent_name = clks->parent_name;109	int ret;110 111	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);112	if (WARN_ON(!periph_clk))113		return NULL;114 115	periph_clk->hw.reg = reg + clks->offset;116 117	init.name = name;118	init.ops = &peri_c_clk_ops;119	init.flags = clks->flags;120 121	init.num_parents = clks->num_parents;122	init.parent_names = parent_name ? &parent_name : NULL;123	if (init.parent_names == NULL)124		init.parent_data = clks->parent_data;125 126	periph_clk->hw.hw.init = &init;127	hw_clk = &periph_clk->hw.hw;128 129	ret = clk_hw_register(NULL, hw_clk);130	if (ret) {131		kfree(periph_clk);132		return ERR_PTR(ret);133	}134	return hw_clk;135}136 137struct clk_hw *n5x_register_periph(const struct n5x_perip_c_clock *clks,138				void __iomem *regbase)139{140	struct clk_hw *hw_clk;141	struct socfpga_periph_clk *periph_clk;142	struct clk_init_data init;143	const char *name = clks->name;144	const char *parent_name = clks->parent_name;145	int ret;146 147	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);148	if (WARN_ON(!periph_clk))149		return NULL;150 151	periph_clk->hw.reg = regbase + clks->offset;152	periph_clk->shift = clks->shift;153 154	init.name = name;155	init.ops = &n5x_peri_c_clk_ops;156	init.flags = clks->flags;157 158	init.num_parents = clks->num_parents;159	init.parent_names = parent_name ? &parent_name : NULL;160 161	periph_clk->hw.hw.init = &init;162	hw_clk = &periph_clk->hw.hw;163 164	ret = clk_hw_register(NULL, hw_clk);165	if (ret) {166		kfree(periph_clk);167		return ERR_PTR(ret);168	}169	return hw_clk;170}171 172struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,173				    void __iomem *regbase)174{175	struct clk_hw *hw_clk;176	struct socfpga_periph_clk *periph_clk;177	struct clk_init_data init;178	const char *name = clks->name;179	const char *parent_name = clks->parent_name;180	int ret;181 182	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);183	if (WARN_ON(!periph_clk))184		return NULL;185 186	if (clks->offset)187		periph_clk->hw.reg = regbase + clks->offset;188	else189		periph_clk->hw.reg = NULL;190 191	if (clks->bypass_reg)192		periph_clk->bypass_reg = regbase + clks->bypass_reg;193	else194		periph_clk->bypass_reg = NULL;195	periph_clk->bypass_shift = clks->bypass_shift;196	periph_clk->fixed_div = clks->fixed_divider;197 198	init.name = name;199	init.ops = &peri_cnt_clk_ops;200	init.flags = clks->flags;201 202	init.num_parents = clks->num_parents;203	init.parent_names = parent_name ? &parent_name : NULL;204	if (init.parent_names == NULL)205		init.parent_data = clks->parent_data;206 207	periph_clk->hw.hw.init = &init;208	hw_clk = &periph_clk->hw.hw;209 210	ret = clk_hw_register(NULL, hw_clk);211	if (ret) {212		kfree(periph_clk);213		return ERR_PTR(ret);214	}215	return hw_clk;216}217