1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2017, Intel Corporation 4 */ 5 #include <linux/slab.h> 6 #include <linux/clk-provider.h> 7 8 #include "stratix10-clk.h" 9 #include "clk.h" 10 11 #define CLK_MGR_FREE_SHIFT 16 12 #define CLK_MGR_FREE_MASK 0x7 13 #define SWCTRLBTCLKSEN_SHIFT 8 14 15 #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw) 16 17 static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk, 18 unsigned long parent_rate) 19 { 20 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); 21 unsigned long div = 1; 22 u32 val; 23 24 val = readl(socfpgaclk->hw.reg); 25 val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0); 26 parent_rate /= val; 27 28 return parent_rate / div; 29 } 30 31 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk, 32 unsigned long parent_rate) 33 { 34 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); 35 unsigned long div = 1; 36 37 if (socfpgaclk->fixed_div) { 38 div = socfpgaclk->fixed_div; 39 } else { 40 if (!socfpgaclk->bypass_reg) 41 div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1); 42 } 43 44 return parent_rate / div; 45 } 46 47 static u8 clk_periclk_get_parent(struct clk_hw *hwclk) 48 { 49 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk); 50 u32 clk_src, mask; 51 u8 parent; 52 53 if (socfpgaclk->bypass_reg) { 54 mask = (0x1 << socfpgaclk->bypass_shift); 55 parent = ((readl(socfpgaclk->bypass_reg) & mask) >> 56 socfpgaclk->bypass_shift); 57 } else { 58 clk_src = readl(socfpgaclk->hw.reg); 59 parent = (clk_src >> CLK_MGR_FREE_SHIFT) & 60 CLK_MGR_FREE_MASK; 61 } 62 return parent; 63 } 64 65 static const struct clk_ops peri_c_clk_ops = { 66 .recalc_rate = clk_peri_c_clk_recalc_rate, 67 .get_parent = clk_periclk_get_parent, 68 }; 69 70 static const struct clk_ops peri_cnt_clk_ops = { 71 .recalc_rate = clk_peri_cnt_clk_recalc_rate, 72 .get_parent = clk_periclk_get_parent, 73 }; 74 75 struct clk *s10_register_periph(const char *name, const char *parent_name, 76 const char * const *parent_names, 77 u8 num_parents, unsigned long flags, 78 void __iomem *reg, unsigned long offset) 79 { 80 struct clk *clk; 81 struct socfpga_periph_clk *periph_clk; 82 struct clk_init_data init; 83 84 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); 85 if (WARN_ON(!periph_clk)) 86 return NULL; 87 88 periph_clk->hw.reg = reg + offset; 89 90 init.name = name; 91 init.ops = &peri_c_clk_ops; 92 init.flags = flags; 93 94 init.num_parents = num_parents; 95 init.parent_names = parent_names ? parent_names : &parent_name; 96 97 periph_clk->hw.hw.init = &init; 98 99 clk = clk_register(NULL, &periph_clk->hw.hw); 100 if (WARN_ON(IS_ERR(clk))) { 101 kfree(periph_clk); 102 return NULL; 103 } 104 return clk; 105 } 106 107 struct clk *s10_register_cnt_periph(const char *name, const char *parent_name, 108 const char * const *parent_names, 109 u8 num_parents, unsigned long flags, 110 void __iomem *regbase, unsigned long offset, 111 u8 fixed_divider, unsigned long bypass_reg, 112 unsigned long bypass_shift) 113 { 114 struct clk *clk; 115 struct socfpga_periph_clk *periph_clk; 116 struct clk_init_data init; 117 118 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL); 119 if (WARN_ON(!periph_clk)) 120 return NULL; 121 122 if (offset) 123 periph_clk->hw.reg = regbase + offset; 124 else 125 periph_clk->hw.reg = NULL; 126 127 if (bypass_reg) 128 periph_clk->bypass_reg = regbase + bypass_reg; 129 else 130 periph_clk->bypass_reg = NULL; 131 periph_clk->bypass_shift = bypass_shift; 132 periph_clk->fixed_div = fixed_divider; 133 134 init.name = name; 135 init.ops = &peri_cnt_clk_ops; 136 init.flags = flags; 137 138 init.num_parents = num_parents; 139 init.parent_names = parent_names ? parent_names : &parent_name; 140 141 periph_clk->hw.hw.init = &init; 142 143 clk = clk_register(NULL, &periph_clk->hw.hw); 144 if (WARN_ON(IS_ERR(clk))) { 145 kfree(periph_clk); 146 return NULL; 147 } 148 return clk; 149 } 150