Linux 4.18.10
[linux/fpc-iii.git] / drivers / clk / socfpga / clk-periph-s10.c
blob568f59b58ddfa94852462ed8fd3531d48fff151c
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>
8 #include "stratix10-clk.h"
9 #include "clk.h"
11 #define CLK_MGR_FREE_SHIFT 16
12 #define CLK_MGR_FREE_MASK 0x7
13 #define SWCTRLBTCLKSEN_SHIFT 8
15 #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
17 static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
18 unsigned long parent_rate)
20 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
21 unsigned long div = 1;
22 u32 val;
24 val = readl(socfpgaclk->hw.reg);
25 val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);
26 parent_rate /= val;
28 return parent_rate / div;
31 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
32 unsigned long parent_rate)
34 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
35 unsigned long div = 1;
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);
44 return parent_rate / div;
47 static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
49 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
50 u32 clk_src, mask;
51 u8 parent;
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;
62 return parent;
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,
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,
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)
80 struct clk *clk;
81 struct socfpga_periph_clk *periph_clk;
82 struct clk_init_data init;
84 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
85 if (WARN_ON(!periph_clk))
86 return NULL;
88 periph_clk->hw.reg = reg + offset;
90 init.name = name;
91 init.ops = &peri_c_clk_ops;
92 init.flags = flags;
94 init.num_parents = num_parents;
95 init.parent_names = parent_names ? parent_names : &parent_name;
97 periph_clk->hw.hw.init = &init;
99 clk = clk_register(NULL, &periph_clk->hw.hw);
100 if (WARN_ON(IS_ERR(clk))) {
101 kfree(periph_clk);
102 return NULL;
104 return clk;
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)
114 struct clk *clk;
115 struct socfpga_periph_clk *periph_clk;
116 struct clk_init_data init;
118 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
119 if (WARN_ON(!periph_clk))
120 return NULL;
122 if (offset)
123 periph_clk->hw.reg = regbase + offset;
124 else
125 periph_clk->hw.reg = NULL;
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;
134 init.name = name;
135 init.ops = &peri_cnt_clk_ops;
136 init.flags = flags;
138 init.num_parents = num_parents;
139 init.parent_names = parent_names ? parent_names : &parent_name;
141 periph_clk->hw.hw.init = &init;
143 clk = clk_register(NULL, &periph_clk->hw.hw);
144 if (WARN_ON(IS_ERR(clk))) {
145 kfree(periph_clk);
146 return NULL;
148 return clk;