Skip to content

Commit 0aa0c95

Browse files
committed
clk: hisilicon: add common clock support
Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is used to support the clock gate that enable/disable/status registers are seperated. Signed-off-by: Haojian Zhuang <[email protected]>
1 parent 6ce4eac commit 0aa0c95

File tree

8 files changed

+823
-0
lines changed

8 files changed

+823
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
* Hisilicon Hi3620 Clock Controller
2+
3+
The Hi3620 clock controller generates and supplies clock to various
4+
controllers within the Hi3620 SoC.
5+
6+
Required Properties:
7+
8+
- compatible: should be one of the following.
9+
- "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
10+
11+
- reg: physical base address of the controller and length of memory mapped
12+
region.
13+
14+
- #clock-cells: should be 1.
15+
16+
Each clock is assigned an identifier and client nodes use this identifier
17+
to specify the clock which they consume.
18+
19+
All these identifier could be found in <dt-bindings/clock/hi3620-clock.h>.

drivers/clk/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
1414
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
1515
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
1616
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
17+
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
1718
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
1819
obj-$(CONFIG_ARCH_MXS) += mxs/
1920
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/

drivers/clk/hisilicon/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#
2+
# Hisilicon Clock specific Makefile
3+
#
4+
5+
obj-y += clk.o clkgate-separated.o clk-hi3620.o

drivers/clk/hisilicon/clk-hi3620.c

Lines changed: 242 additions & 0 deletions
Large diffs are not rendered by default.

drivers/clk/hisilicon/clk.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Hisilicon clock driver
3+
*
4+
* Copyright (c) 2012-2013 Hisilicon Limited.
5+
* Copyright (c) 2012-2013 Linaro Limited.
6+
*
7+
* Author: Haojian Zhuang <[email protected]>
8+
* Xin Li <[email protected]>
9+
*
10+
* This program is free software; you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation; either version 2 of the License, or
13+
* (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License along
21+
* with this program; if not, write to the Free Software Foundation, Inc.,
22+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23+
*
24+
*/
25+
26+
#include <linux/kernel.h>
27+
#include <linux/clk-provider.h>
28+
#include <linux/clkdev.h>
29+
#include <linux/delay.h>
30+
#include <linux/io.h>
31+
#include <linux/of.h>
32+
#include <linux/of_address.h>
33+
#include <linux/of_device.h>
34+
#include <linux/slab.h>
35+
#include <linux/clk.h>
36+
37+
#include "clk.h"
38+
39+
static DEFINE_SPINLOCK(hisi_clk_lock);
40+
static struct clk **clk_table;
41+
static struct clk_onecell_data clk_data;
42+
43+
void __init hisi_clk_init(struct device_node *np, int nr_clks)
44+
{
45+
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
46+
if (!clk_table) {
47+
pr_err("%s: could not allocate clock lookup table\n", __func__);
48+
return;
49+
}
50+
clk_data.clks = clk_table;
51+
clk_data.clk_num = nr_clks;
52+
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
53+
}
54+
55+
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
56+
int nums, void __iomem *base)
57+
{
58+
struct clk *clk;
59+
int i;
60+
61+
for (i = 0; i < nums; i++) {
62+
clk = clk_register_fixed_rate(NULL, clks[i].name,
63+
clks[i].parent_name,
64+
clks[i].flags,
65+
clks[i].fixed_rate);
66+
if (IS_ERR(clk)) {
67+
pr_err("%s: failed to register clock %s\n",
68+
__func__, clks[i].name);
69+
continue;
70+
}
71+
}
72+
}
73+
74+
void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
75+
int nums, void __iomem *base)
76+
{
77+
struct clk *clk;
78+
int i;
79+
80+
for (i = 0; i < nums; i++) {
81+
clk = clk_register_fixed_factor(NULL, clks[i].name,
82+
clks[i].parent_name,
83+
clks[i].flags, clks[i].mult,
84+
clks[i].div);
85+
if (IS_ERR(clk)) {
86+
pr_err("%s: failed to register clock %s\n",
87+
__func__, clks[i].name);
88+
continue;
89+
}
90+
}
91+
}
92+
93+
void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
94+
int nums, void __iomem *base)
95+
{
96+
struct clk *clk;
97+
int i;
98+
99+
for (i = 0; i < nums; i++) {
100+
clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names,
101+
clks[i].num_parents, clks[i].flags,
102+
base + clks[i].offset, clks[i].shift,
103+
clks[i].width, clks[i].mux_flags,
104+
&hisi_clk_lock);
105+
if (IS_ERR(clk)) {
106+
pr_err("%s: failed to register clock %s\n",
107+
__func__, clks[i].name);
108+
continue;
109+
}
110+
111+
if (clks[i].alias)
112+
clk_register_clkdev(clk, clks[i].alias, NULL);
113+
114+
clk_table[clks[i].id] = clk;
115+
}
116+
}
117+
118+
void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
119+
int nums, void __iomem *base)
120+
{
121+
struct clk *clk;
122+
int i;
123+
124+
for (i = 0; i < nums; i++) {
125+
clk = clk_register_divider_table(NULL, clks[i].name,
126+
clks[i].parent_name,
127+
clks[i].flags,
128+
base + clks[i].offset,
129+
clks[i].shift, clks[i].width,
130+
clks[i].div_flags,
131+
clks[i].table,
132+
&hisi_clk_lock);
133+
if (IS_ERR(clk)) {
134+
pr_err("%s: failed to register clock %s\n",
135+
__func__, clks[i].name);
136+
continue;
137+
}
138+
139+
if (clks[i].alias)
140+
clk_register_clkdev(clk, clks[i].alias, NULL);
141+
142+
clk_table[clks[i].id] = clk;
143+
}
144+
}
145+
146+
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
147+
int nums, void __iomem *base)
148+
{
149+
struct clk *clk;
150+
int i;
151+
152+
for (i = 0; i < nums; i++) {
153+
clk = hisi_register_clkgate_sep(NULL, clks[i].name,
154+
clks[i].parent_name,
155+
clks[i].flags,
156+
base + clks[i].offset,
157+
clks[i].bit_idx,
158+
clks[i].gate_flags,
159+
&hisi_clk_lock);
160+
if (IS_ERR(clk)) {
161+
pr_err("%s: failed to register clock %s\n",
162+
__func__, clks[i].name);
163+
continue;
164+
}
165+
166+
if (clks[i].alias)
167+
clk_register_clkdev(clk, clks[i].alias, NULL);
168+
169+
clk_table[clks[i].id] = clk;
170+
}
171+
}

drivers/clk/hisilicon/clk.h

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Hisilicon Hi3620 clock gate driver
3+
*
4+
* Copyright (c) 2012-2013 Hisilicon Limited.
5+
* Copyright (c) 2012-2013 Linaro Limited.
6+
*
7+
* Author: Haojian Zhuang <[email protected]>
8+
* Xin Li <[email protected]>
9+
*
10+
* This program is free software; you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation; either version 2 of the License, or
13+
* (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License along
21+
* with this program; if not, write to the Free Software Foundation, Inc.,
22+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23+
*
24+
*/
25+
26+
#ifndef __HISI_CLK_H
27+
#define __HISI_CLK_H
28+
29+
#include <linux/clk-provider.h>
30+
#include <linux/io.h>
31+
#include <linux/spinlock.h>
32+
33+
struct hisi_fixed_rate_clock {
34+
unsigned int id;
35+
char *name;
36+
const char *parent_name;
37+
unsigned long flags;
38+
unsigned long fixed_rate;
39+
};
40+
41+
struct hisi_fixed_factor_clock {
42+
unsigned int id;
43+
char *name;
44+
const char *parent_name;
45+
unsigned long mult;
46+
unsigned long div;
47+
unsigned long flags;
48+
};
49+
50+
struct hisi_mux_clock {
51+
unsigned int id;
52+
const char *name;
53+
const char **parent_names;
54+
u8 num_parents;
55+
unsigned long flags;
56+
unsigned long offset;
57+
u8 shift;
58+
u8 width;
59+
u8 mux_flags;
60+
const char *alias;
61+
};
62+
63+
struct hisi_divider_clock {
64+
unsigned int id;
65+
const char *name;
66+
const char *parent_name;
67+
unsigned long flags;
68+
unsigned long offset;
69+
u8 shift;
70+
u8 width;
71+
u8 div_flags;
72+
struct clk_div_table *table;
73+
const char *alias;
74+
};
75+
76+
struct hisi_gate_clock {
77+
unsigned int id;
78+
const char *name;
79+
const char *parent_name;
80+
unsigned long flags;
81+
unsigned long offset;
82+
u8 bit_idx;
83+
u8 gate_flags;
84+
const char *alias;
85+
};
86+
87+
struct clk *hisi_register_clkgate_sep(struct device *, const char *,
88+
const char *, unsigned long,
89+
void __iomem *, u8,
90+
u8, spinlock_t *);
91+
92+
void __init hisi_clk_init(struct device_node *, int);
93+
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
94+
int, void __iomem *);
95+
void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
96+
int, void __iomem *);
97+
void __init hisi_clk_register_mux(struct hisi_mux_clock *, int,
98+
void __iomem *);
99+
void __init hisi_clk_register_divider(struct hisi_divider_clock *,
100+
int, void __iomem *);
101+
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
102+
int, void __iomem *);
103+
#endif /* __HISI_CLK_H */

0 commit comments

Comments
 (0)