2 * Copyright (C) 2010 Broadcom
3 * Copyright (C) 2012 Stephen Warren
4 * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <linux/clk-provider.h>
20 #include <linux/kernel.h>
21 #include <linux/init.h>
23 #include <linux/of_device.h>
24 #include <linux/platform_device.h>
25 #include <linux/stringify.h>
26 #include <linux/regmap.h>
27 #include <linux/mfd/syscon.h>
29 #include <dt-bindings/clock/oxsemi,ox810se.h>
30 #include <dt-bindings/clock/oxsemi,ox820.h>
32 /* Standard regmap gate clocks */
33 struct clk_oxnas_gate
{
36 struct regmap
*regmap
;
39 struct oxnas_stdclk_data
{
40 struct clk_hw_onecell_data
*onecell_data
;
41 struct clk_oxnas_gate
**gates
;
43 struct clk_oxnas_pll
**plls
;
48 #define CLK_STAT_REGOFFSET 0x24
49 #define CLK_SET_REGOFFSET 0x2c
50 #define CLK_CLR_REGOFFSET 0x30
52 static inline struct clk_oxnas_gate
*to_clk_oxnas_gate(struct clk_hw
*hw
)
54 return container_of(hw
, struct clk_oxnas_gate
, hw
);
57 static int oxnas_clk_gate_is_enabled(struct clk_hw
*hw
)
59 struct clk_oxnas_gate
*std
= to_clk_oxnas_gate(hw
);
63 ret
= regmap_read(std
->regmap
, CLK_STAT_REGOFFSET
, &val
);
67 return val
& BIT(std
->bit
);
70 static int oxnas_clk_gate_enable(struct clk_hw
*hw
)
72 struct clk_oxnas_gate
*std
= to_clk_oxnas_gate(hw
);
74 regmap_write(std
->regmap
, CLK_SET_REGOFFSET
, BIT(std
->bit
));
79 static void oxnas_clk_gate_disable(struct clk_hw
*hw
)
81 struct clk_oxnas_gate
*std
= to_clk_oxnas_gate(hw
);
83 regmap_write(std
->regmap
, CLK_CLR_REGOFFSET
, BIT(std
->bit
));
86 static const struct clk_ops oxnas_clk_gate_ops
= {
87 .enable
= oxnas_clk_gate_enable
,
88 .disable
= oxnas_clk_gate_disable
,
89 .is_enabled
= oxnas_clk_gate_is_enabled
,
92 static const char *const osc_parents
[] = {
96 static const char *const eth_parents
[] = {
100 #define OXNAS_GATE(_name, _bit, _parents) \
101 struct clk_oxnas_gate _name = { \
103 .hw.init = &(struct clk_init_data) { \
105 .ops = &oxnas_clk_gate_ops, \
106 .parent_names = _parents, \
107 .num_parents = ARRAY_SIZE(_parents), \
108 .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
112 static OXNAS_GATE(ox810se_leon
, 0, osc_parents
);
113 static OXNAS_GATE(ox810se_dma_sgdma
, 1, osc_parents
);
114 static OXNAS_GATE(ox810se_cipher
, 2, osc_parents
);
115 static OXNAS_GATE(ox810se_sata
, 4, osc_parents
);
116 static OXNAS_GATE(ox810se_audio
, 5, osc_parents
);
117 static OXNAS_GATE(ox810se_usbmph
, 6, osc_parents
);
118 static OXNAS_GATE(ox810se_etha
, 7, eth_parents
);
119 static OXNAS_GATE(ox810se_pciea
, 8, osc_parents
);
120 static OXNAS_GATE(ox810se_nand
, 9, osc_parents
);
122 static struct clk_oxnas_gate
*ox810se_gates
[] = {
134 static OXNAS_GATE(ox820_leon
, 0, osc_parents
);
135 static OXNAS_GATE(ox820_dma_sgdma
, 1, osc_parents
);
136 static OXNAS_GATE(ox820_cipher
, 2, osc_parents
);
137 static OXNAS_GATE(ox820_sd
, 3, osc_parents
);
138 static OXNAS_GATE(ox820_sata
, 4, osc_parents
);
139 static OXNAS_GATE(ox820_audio
, 5, osc_parents
);
140 static OXNAS_GATE(ox820_usbmph
, 6, osc_parents
);
141 static OXNAS_GATE(ox820_etha
, 7, eth_parents
);
142 static OXNAS_GATE(ox820_pciea
, 8, osc_parents
);
143 static OXNAS_GATE(ox820_nand
, 9, osc_parents
);
144 static OXNAS_GATE(ox820_ethb
, 10, eth_parents
);
145 static OXNAS_GATE(ox820_pcieb
, 11, osc_parents
);
146 static OXNAS_GATE(ox820_ref600
, 12, osc_parents
);
147 static OXNAS_GATE(ox820_usbdev
, 13, osc_parents
);
149 static struct clk_oxnas_gate
*ox820_gates
[] = {
166 static struct clk_hw_onecell_data ox810se_hw_onecell_data
= {
168 [CLK_810_LEON
] = &ox810se_leon
.hw
,
169 [CLK_810_DMA_SGDMA
] = &ox810se_dma_sgdma
.hw
,
170 [CLK_810_CIPHER
] = &ox810se_cipher
.hw
,
171 [CLK_810_SATA
] = &ox810se_sata
.hw
,
172 [CLK_810_AUDIO
] = &ox810se_audio
.hw
,
173 [CLK_810_USBMPH
] = &ox810se_usbmph
.hw
,
174 [CLK_810_ETHA
] = &ox810se_etha
.hw
,
175 [CLK_810_PCIEA
] = &ox810se_pciea
.hw
,
176 [CLK_810_NAND
] = &ox810se_nand
.hw
,
178 .num
= ARRAY_SIZE(ox810se_gates
),
181 static struct clk_hw_onecell_data ox820_hw_onecell_data
= {
183 [CLK_820_LEON
] = &ox820_leon
.hw
,
184 [CLK_820_DMA_SGDMA
] = &ox820_dma_sgdma
.hw
,
185 [CLK_820_CIPHER
] = &ox820_cipher
.hw
,
186 [CLK_820_SD
] = &ox820_sd
.hw
,
187 [CLK_820_SATA
] = &ox820_sata
.hw
,
188 [CLK_820_AUDIO
] = &ox820_audio
.hw
,
189 [CLK_820_USBMPH
] = &ox820_usbmph
.hw
,
190 [CLK_820_ETHA
] = &ox820_etha
.hw
,
191 [CLK_820_PCIEA
] = &ox820_pciea
.hw
,
192 [CLK_820_NAND
] = &ox820_nand
.hw
,
193 [CLK_820_ETHB
] = &ox820_ethb
.hw
,
194 [CLK_820_PCIEB
] = &ox820_pcieb
.hw
,
195 [CLK_820_REF600
] = &ox820_ref600
.hw
,
196 [CLK_820_USBDEV
] = &ox820_usbdev
.hw
,
198 .num
= ARRAY_SIZE(ox820_gates
),
201 static struct oxnas_stdclk_data ox810se_stdclk_data
= {
202 .onecell_data
= &ox810se_hw_onecell_data
,
203 .gates
= ox810se_gates
,
204 .ngates
= ARRAY_SIZE(ox810se_gates
),
207 static struct oxnas_stdclk_data ox820_stdclk_data
= {
208 .onecell_data
= &ox820_hw_onecell_data
,
209 .gates
= ox820_gates
,
210 .ngates
= ARRAY_SIZE(ox820_gates
),
213 static const struct of_device_id oxnas_stdclk_dt_ids
[] = {
214 { .compatible
= "oxsemi,ox810se-stdclk", &ox810se_stdclk_data
},
215 { .compatible
= "oxsemi,ox820-stdclk", &ox820_stdclk_data
},
219 static int oxnas_stdclk_probe(struct platform_device
*pdev
)
221 struct device_node
*np
= pdev
->dev
.of_node
;
222 const struct oxnas_stdclk_data
*data
;
223 const struct of_device_id
*id
;
224 struct regmap
*regmap
;
228 id
= of_match_device(oxnas_stdclk_dt_ids
, &pdev
->dev
);
233 regmap
= syscon_node_to_regmap(of_get_parent(np
));
234 if (IS_ERR(regmap
)) {
235 dev_err(&pdev
->dev
, "failed to have parent regmap\n");
236 return PTR_ERR(regmap
);
239 for (i
= 0 ; i
< data
->ngates
; ++i
)
240 data
->gates
[i
]->regmap
= regmap
;
242 for (i
= 0; i
< data
->onecell_data
->num
; i
++) {
243 if (!data
->onecell_data
->hws
[i
])
246 ret
= devm_clk_hw_register(&pdev
->dev
,
247 data
->onecell_data
->hws
[i
]);
252 return of_clk_add_hw_provider(np
, of_clk_hw_onecell_get
,
256 static struct platform_driver oxnas_stdclk_driver
= {
257 .probe
= oxnas_stdclk_probe
,
259 .name
= "oxnas-stdclk",
260 .suppress_bind_attrs
= true,
261 .of_match_table
= oxnas_stdclk_dt_ids
,
264 builtin_platform_driver(oxnas_stdclk_driver
);