1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/io.h>
18#include <linux/clk.h>
19#include <linux/clk-provider.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/delay.h>
23#include <linux/export.h>
24#include <linux/clk/tegra.h>
25
26#include "clk.h"
27#include "clk-id.h"
28
29#define OSC_CTRL 0x50
30#define OSC_CTRL_OSC_FREQ_SHIFT 28
31#define OSC_CTRL_PLL_REF_DIV_SHIFT 26
32
33int __init tegra_osc_clk_init(void __iomem *clk_base,
34 struct tegra_clk *tegra_clks,
35 unsigned long *input_freqs, int num,
36 unsigned long *osc_freq,
37 unsigned long *pll_ref_freq)
38{
39 struct clk *clk;
40 struct clk **dt_clk;
41 u32 val, pll_ref_div;
42 unsigned osc_idx;
43
44 val = readl_relaxed(clk_base + OSC_CTRL);
45 osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
46
47 if (osc_idx < num)
48 *osc_freq = input_freqs[osc_idx];
49 else
50 *osc_freq = 0;
51
52 if (!*osc_freq) {
53 WARN_ON(1);
54 return -EINVAL;
55 }
56
57 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, tegra_clks);
58 if (!dt_clk)
59 return 0;
60
61 clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT,
62 *osc_freq);
63 *dt_clk = clk;
64
65
66 val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
67 pll_ref_div = 1 << val;
68 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, tegra_clks);
69 if (!dt_clk)
70 return 0;
71
72 clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m",
73 0, 1, pll_ref_div);
74 *dt_clk = clk;
75
76 if (pll_ref_freq)
77 *pll_ref_freq = *osc_freq / pll_ref_div;
78
79 return 0;
80}
81
82void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)
83{
84 struct clk *clk;
85 struct clk **dt_clk;
86
87
88 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks);
89 if (dt_clk) {
90 clk = clk_register_fixed_rate(NULL, "clk_32k", NULL,
91 CLK_IS_ROOT, 32768);
92 *dt_clk = clk;
93 }
94
95
96 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks);
97 if (dt_clk) {
98 clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m",
99 CLK_SET_RATE_PARENT, 1, 2);
100 *dt_clk = clk;
101 }
102
103
104 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks);
105 if (dt_clk) {
106 clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m",
107 CLK_SET_RATE_PARENT, 1, 4);
108 *dt_clk = clk;
109 }
110}
111
112