1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Hi3798CV200 Clock and Reset Generator Driver
4 *
5 * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
6 */
7
8#include <dt-bindings/clock/histb-clock.h>
9#include <linux/clk-provider.h>
10#include <linux/module.h>
11#include <linux/of_device.h>
12#include <linux/platform_device.h>
13#include "clk.h"
14#include "crg.h"
15#include "reset.h"
16
17/* hi3798CV200 core CRG */
18#define HI3798CV200_INNER_CLK_OFFSET		64
19#define HI3798CV200_FIXED_24M			65
20#define HI3798CV200_FIXED_25M			66
21#define HI3798CV200_FIXED_50M			67
22#define HI3798CV200_FIXED_75M			68
23#define HI3798CV200_FIXED_100M			69
24#define HI3798CV200_FIXED_150M			70
25#define HI3798CV200_FIXED_200M			71
26#define HI3798CV200_FIXED_250M			72
27#define HI3798CV200_FIXED_300M			73
28#define HI3798CV200_FIXED_400M			74
29#define HI3798CV200_MMC_MUX			75
30#define HI3798CV200_ETH_PUB_CLK			76
31#define HI3798CV200_ETH_BUS_CLK			77
32#define HI3798CV200_ETH_BUS0_CLK		78
33#define HI3798CV200_ETH_BUS1_CLK		79
34#define HI3798CV200_COMBPHY1_MUX		80
35#define HI3798CV200_FIXED_12M			81
36#define HI3798CV200_FIXED_48M			82
37#define HI3798CV200_FIXED_60M			83
38#define HI3798CV200_FIXED_166P5M		84
39#define HI3798CV200_SDIO0_MUX			85
40#define HI3798CV200_COMBPHY0_MUX		86
41
42#define HI3798CV200_CRG_NR_CLKS			128
43
44static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = {
45	{ HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, },
46	{ HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, },
47	{ HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, },
48	{ HI3798CV200_FIXED_12M, "12m", NULL, 0, 12000000, },
49	{ HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, },
50	{ HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, },
51	{ HI3798CV200_FIXED_48M, "48m", NULL, 0, 48000000, },
52	{ HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, },
53	{ HI3798CV200_FIXED_60M, "60m", NULL, 0, 60000000, },
54	{ HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, },
55	{ HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, },
56	{ HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, },
57	{ HI3798CV200_FIXED_166P5M, "166p5m", NULL, 0, 165000000, },
58	{ HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, },
59	{ HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, },
60};
61
62static const char *const mmc_mux_p[] = {
63		"100m", "50m", "25m", "200m", "150m" };
64static u32 mmc_mux_table[] = {0, 1, 2, 3, 6};
65
66static const char *const comphy_mux_p[] = {
67		"100m", "25m"};
68static u32 comphy_mux_table[] = {2, 3};
69
70static const char *const sdio_mux_p[] = {
71		"100m", "50m", "150m", "166p5m" };
72static u32 sdio_mux_table[] = {0, 1, 2, 3};
73
74static struct hisi_mux_clock hi3798cv200_mux_clks[] = {
75	{ HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
76		CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, },
77	{ HI3798CV200_COMBPHY0_MUX, "combphy0_mux",
78		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
79		CLK_SET_RATE_PARENT, 0x188, 2, 2, 0, comphy_mux_table, },
80	{ HI3798CV200_COMBPHY1_MUX, "combphy1_mux",
81		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
82		CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy_mux_table, },
83	{ HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p,
84		ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT,
85		0x9c, 8, 2, 0, sdio_mux_table, },
86};
87
88static u32 mmc_phase_regvals[] = {0, 1, 2, 3, 4, 5, 6, 7};
89static u32 mmc_phase_degrees[] = {0, 45, 90, 135, 180, 225, 270, 315};
90
91static struct hisi_phase_clock hi3798cv200_phase_clks[] = {
92	{ HISTB_MMC_SAMPLE_CLK, "mmc_sample", "clk_mmc_ciu",
93		CLK_SET_RATE_PARENT, 0xa0, 12, 3, mmc_phase_degrees,
94		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
95	{ HISTB_MMC_DRV_CLK, "mmc_drive", "clk_mmc_ciu",
96		CLK_SET_RATE_PARENT, 0xa0, 16, 3, mmc_phase_degrees,
97		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
98};
99
100static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
101	/* UART */
102	{ HISTB_UART2_CLK, "clk_uart2", "75m",
103		CLK_SET_RATE_PARENT, 0x68, 4, 0, },
104	/* I2C */
105	{ HISTB_I2C0_CLK, "clk_i2c0", "clk_apb",
106		CLK_SET_RATE_PARENT, 0x6C, 4, 0, },
107	{ HISTB_I2C1_CLK, "clk_i2c1", "clk_apb",
108		CLK_SET_RATE_PARENT, 0x6C, 8, 0, },
109	{ HISTB_I2C2_CLK, "clk_i2c2", "clk_apb",
110		CLK_SET_RATE_PARENT, 0x6C, 12, 0, },
111	{ HISTB_I2C3_CLK, "clk_i2c3", "clk_apb",
112		CLK_SET_RATE_PARENT, 0x6C, 16, 0, },
113	{ HISTB_I2C4_CLK, "clk_i2c4", "clk_apb",
114		CLK_SET_RATE_PARENT, 0x6C, 20, 0, },
115	/* SPI */
116	{ HISTB_SPI0_CLK, "clk_spi0", "clk_apb",
117		CLK_SET_RATE_PARENT, 0x70, 0, 0, },
118	/* SDIO */
119	{ HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m",
120			CLK_SET_RATE_PARENT, 0x9c, 0, 0, },
121	{ HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "sdio0_mux",
122		CLK_SET_RATE_PARENT, 0x9c, 1, 0, },
123	/* EMMC */
124	{ HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m",
125		CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
126	{ HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
127		CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
128	/* PCIE*/
129	{ HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m",
130		CLK_SET_RATE_PARENT, 0x18c, 0, 0, },
131	{ HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m",
132		CLK_SET_RATE_PARENT, 0x18c, 1, 0, },
133	{ HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m",
134		CLK_SET_RATE_PARENT, 0x18c, 2, 0, },
135	{ HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m",
136		CLK_SET_RATE_PARENT, 0x18c, 3, 0, },
137	/* Ethernet */
138	{ HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL,
139		CLK_SET_RATE_PARENT, 0xcc, 5, 0, },
140	{ HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub",
141		CLK_SET_RATE_PARENT, 0xcc, 0, 0, },
142	{ HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus",
143		CLK_SET_RATE_PARENT, 0xcc, 1, 0, },
144	{ HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus",
145		CLK_SET_RATE_PARENT, 0xcc, 2, 0, },
146	{ HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0",
147		CLK_SET_RATE_PARENT, 0xcc, 3, 0, },
148	{ HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0",
149		CLK_SET_RATE_PARENT, 0xcc, 24, 0, },
150	{ HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1",
151		CLK_SET_RATE_PARENT, 0xcc, 4, 0, },
152	{ HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1",
153		CLK_SET_RATE_PARENT, 0xcc, 25, 0, },
154	/* COMBPHY0 */
155	{ HISTB_COMBPHY0_CLK, "clk_combphy0", "combphy0_mux",
156		CLK_SET_RATE_PARENT, 0x188, 0, 0, },
157	/* COMBPHY1 */
158	{ HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux",
159		CLK_SET_RATE_PARENT, 0x188, 8, 0, },
160	/* USB2 */
161	{ HISTB_USB2_BUS_CLK, "clk_u2_bus", "clk_ahb",
162		CLK_SET_RATE_PARENT, 0xb8, 0, 0, },
163	{ HISTB_USB2_PHY_CLK, "clk_u2_phy", "60m",
164		CLK_SET_RATE_PARENT, 0xb8, 4, 0, },
165	{ HISTB_USB2_12M_CLK, "clk_u2_12m", "12m",
166		CLK_SET_RATE_PARENT, 0xb8, 2, 0 },
167	{ HISTB_USB2_48M_CLK, "clk_u2_48m", "48m",
168		CLK_SET_RATE_PARENT, 0xb8, 1, 0 },
169	{ HISTB_USB2_UTMI_CLK, "clk_u2_utmi", "60m",
170		CLK_SET_RATE_PARENT, 0xb8, 5, 0 },
171	{ HISTB_USB2_OTG_UTMI_CLK, "clk_u2_otg_utmi", "60m",
172		CLK_SET_RATE_PARENT, 0xb8, 3, 0 },
173	{ HISTB_USB2_PHY1_REF_CLK, "clk_u2_phy1_ref", "24m",
174		CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
175	{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
176		CLK_SET_RATE_PARENT, 0xbc, 2, 0 },
177	/* USB3 */
178	{ HISTB_USB3_BUS_CLK, "clk_u3_bus", NULL,
179		CLK_SET_RATE_PARENT, 0xb0, 0, 0 },
180	{ HISTB_USB3_UTMI_CLK, "clk_u3_utmi", NULL,
181		CLK_SET_RATE_PARENT, 0xb0, 4, 0 },
182	{ HISTB_USB3_PIPE_CLK, "clk_u3_pipe", NULL,
183		CLK_SET_RATE_PARENT, 0xb0, 3, 0 },
184	{ HISTB_USB3_SUSPEND_CLK, "clk_u3_suspend", NULL,
185		CLK_SET_RATE_PARENT, 0xb0, 2, 0 },
186	{ HISTB_USB3_BUS_CLK1, "clk_u3_bus1", NULL,
187		CLK_SET_RATE_PARENT, 0xb0, 16, 0 },
188	{ HISTB_USB3_UTMI_CLK1, "clk_u3_utmi1", NULL,
189		CLK_SET_RATE_PARENT, 0xb0, 20, 0 },
190	{ HISTB_USB3_PIPE_CLK1, "clk_u3_pipe1", NULL,
191		CLK_SET_RATE_PARENT, 0xb0, 19, 0 },
192	{ HISTB_USB3_SUSPEND_CLK1, "clk_u3_suspend1", NULL,
193		CLK_SET_RATE_PARENT, 0xb0, 18, 0 },
194};
195
196static struct hisi_clock_data *hi3798cv200_clk_register(
197				struct platform_device *pdev)
198{
199	struct hisi_clock_data *clk_data;
200	int ret;
201
202	clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS);
203	if (!clk_data)
204		return ERR_PTR(-ENOMEM);
205
206	/* hisi_phase_clock is resource managed */
207	ret = hisi_clk_register_phase(&pdev->dev,
208				hi3798cv200_phase_clks,
209				ARRAY_SIZE(hi3798cv200_phase_clks),
210				clk_data);
211	if (ret)
212		return ERR_PTR(ret);
213
214	ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks,
215				     ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
216				     clk_data);
217	if (ret)
218		return ERR_PTR(ret);
219
220	ret = hisi_clk_register_mux(hi3798cv200_mux_clks,
221				ARRAY_SIZE(hi3798cv200_mux_clks),
222				clk_data);
223	if (ret)
224		goto unregister_fixed_rate;
225
226	ret = hisi_clk_register_gate(hi3798cv200_gate_clks,
227				ARRAY_SIZE(hi3798cv200_gate_clks),
228				clk_data);
229	if (ret)
230		goto unregister_mux;
231
232	ret = of_clk_add_provider(pdev->dev.of_node,
233			of_clk_src_onecell_get, &clk_data->clk_data);
234	if (ret)
235		goto unregister_gate;
236
237	return clk_data;
238
239unregister_gate:
240	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
241				ARRAY_SIZE(hi3798cv200_gate_clks),
242				clk_data);
243unregister_mux:
244	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
245				ARRAY_SIZE(hi3798cv200_mux_clks),
246				clk_data);
247unregister_fixed_rate:
248	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
249				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
250				clk_data);
251	return ERR_PTR(ret);
252}
253
254static void hi3798cv200_clk_unregister(struct platform_device *pdev)
255{
256	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
257
258	of_clk_del_provider(pdev->dev.of_node);
259
260	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
261				ARRAY_SIZE(hi3798cv200_gate_clks),
262				crg->clk_data);
263	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
264				ARRAY_SIZE(hi3798cv200_mux_clks),
265				crg->clk_data);
266	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
267				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
268				crg->clk_data);
269}
270
271static const struct hisi_crg_funcs hi3798cv200_crg_funcs = {
272	.register_clks = hi3798cv200_clk_register,
273	.unregister_clks = hi3798cv200_clk_unregister,
274};
275
276/* hi3798CV200 sysctrl CRG */
277
278#define HI3798CV200_SYSCTRL_NR_CLKS 16
279
280static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = {
281	{ HISTB_IR_CLK, "clk_ir", "24m",
282		CLK_SET_RATE_PARENT, 0x48, 4, 0, },
283	{ HISTB_TIMER01_CLK, "clk_timer01", "24m",
284		CLK_SET_RATE_PARENT, 0x48, 6, 0, },
285	{ HISTB_UART0_CLK, "clk_uart0", "75m",
286		CLK_SET_RATE_PARENT, 0x48, 10, 0, },
287};
288
289static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register(
290					struct platform_device *pdev)
291{
292	struct hisi_clock_data *clk_data;
293	int ret;
294
295	clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS);
296	if (!clk_data)
297		return ERR_PTR(-ENOMEM);
298
299	ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks,
300				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
301				clk_data);
302	if (ret)
303		return ERR_PTR(ret);
304
305	ret = of_clk_add_provider(pdev->dev.of_node,
306			of_clk_src_onecell_get, &clk_data->clk_data);
307	if (ret)
308		goto unregister_gate;
309
310	return clk_data;
311
312unregister_gate:
313	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
314				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
315				clk_data);
316	return ERR_PTR(ret);
317}
318
319static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev)
320{
321	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
322
323	of_clk_del_provider(pdev->dev.of_node);
324
325	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
326				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
327				crg->clk_data);
328}
329
330static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = {
331	.register_clks = hi3798cv200_sysctrl_clk_register,
332	.unregister_clks = hi3798cv200_sysctrl_clk_unregister,
333};
334
335static const struct of_device_id hi3798cv200_crg_match_table[] = {
336	{ .compatible = "hisilicon,hi3798cv200-crg",
337		.data = &hi3798cv200_crg_funcs },
338	{ .compatible = "hisilicon,hi3798cv200-sysctrl",
339		.data = &hi3798cv200_sysctrl_funcs },
340	{ }
341};
342MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table);
343
344static int hi3798cv200_crg_probe(struct platform_device *pdev)
345{
346	struct hisi_crg_dev *crg;
347
348	crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
349	if (!crg)
350		return -ENOMEM;
351
352	crg->funcs = of_device_get_match_data(&pdev->dev);
353	if (!crg->funcs)
354		return -ENOENT;
355
356	crg->rstc = hisi_reset_init(pdev);
357	if (!crg->rstc)
358		return -ENOMEM;
359
360	crg->clk_data = crg->funcs->register_clks(pdev);
361	if (IS_ERR(crg->clk_data)) {
362		hisi_reset_exit(crg->rstc);
363		return PTR_ERR(crg->clk_data);
364	}
365
366	platform_set_drvdata(pdev, crg);
367	return 0;
368}
369
370static int hi3798cv200_crg_remove(struct platform_device *pdev)
371{
372	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
373
374	hisi_reset_exit(crg->rstc);
375	crg->funcs->unregister_clks(pdev);
376	return 0;
377}
378
379static struct platform_driver hi3798cv200_crg_driver = {
380	.probe          = hi3798cv200_crg_probe,
381	.remove		= hi3798cv200_crg_remove,
382	.driver         = {
383		.name   = "hi3798cv200-crg",
384		.of_match_table = hi3798cv200_crg_match_table,
385	},
386};
387
388static int __init hi3798cv200_crg_init(void)
389{
390	return platform_driver_register(&hi3798cv200_crg_driver);
391}
392core_initcall(hi3798cv200_crg_init);
393
394static void __exit hi3798cv200_crg_exit(void)
395{
396	platform_driver_unregister(&hi3798cv200_crg_driver);
397}
398module_exit(hi3798cv200_crg_exit);
399
400MODULE_LICENSE("GPL v2");
401MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver");
402