xref: /openbmc/linux/drivers/clk/hisilicon/crg-hi3798cv200.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2707d33cbSJiancheng Xue /*
3707d33cbSJiancheng Xue  * Hi3798CV200 Clock and Reset Generator Driver
4707d33cbSJiancheng Xue  *
5707d33cbSJiancheng Xue  * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
6707d33cbSJiancheng Xue  */
7707d33cbSJiancheng Xue 
8707d33cbSJiancheng Xue #include <dt-bindings/clock/histb-clock.h>
9707d33cbSJiancheng Xue #include <linux/clk-provider.h>
10707d33cbSJiancheng Xue #include <linux/module.h>
11*a96cbb14SRob Herring #include <linux/of.h>
12707d33cbSJiancheng Xue #include <linux/platform_device.h>
13707d33cbSJiancheng Xue #include "clk.h"
14707d33cbSJiancheng Xue #include "crg.h"
15707d33cbSJiancheng Xue #include "reset.h"
16707d33cbSJiancheng Xue 
17707d33cbSJiancheng Xue /* hi3798CV200 core CRG */
18707d33cbSJiancheng Xue #define HI3798CV200_INNER_CLK_OFFSET		64
19707d33cbSJiancheng Xue #define HI3798CV200_FIXED_24M			65
20707d33cbSJiancheng Xue #define HI3798CV200_FIXED_25M			66
21707d33cbSJiancheng Xue #define HI3798CV200_FIXED_50M			67
22707d33cbSJiancheng Xue #define HI3798CV200_FIXED_75M			68
23707d33cbSJiancheng Xue #define HI3798CV200_FIXED_100M			69
24707d33cbSJiancheng Xue #define HI3798CV200_FIXED_150M			70
25707d33cbSJiancheng Xue #define HI3798CV200_FIXED_200M			71
26707d33cbSJiancheng Xue #define HI3798CV200_FIXED_250M			72
27707d33cbSJiancheng Xue #define HI3798CV200_FIXED_300M			73
28707d33cbSJiancheng Xue #define HI3798CV200_FIXED_400M			74
29707d33cbSJiancheng Xue #define HI3798CV200_MMC_MUX			75
30707d33cbSJiancheng Xue #define HI3798CV200_ETH_PUB_CLK			76
31707d33cbSJiancheng Xue #define HI3798CV200_ETH_BUS_CLK			77
32707d33cbSJiancheng Xue #define HI3798CV200_ETH_BUS0_CLK		78
33707d33cbSJiancheng Xue #define HI3798CV200_ETH_BUS1_CLK		79
34707d33cbSJiancheng Xue #define HI3798CV200_COMBPHY1_MUX		80
350d846596SJiancheng Xue #define HI3798CV200_FIXED_12M			81
360d846596SJiancheng Xue #define HI3798CV200_FIXED_48M			82
370d846596SJiancheng Xue #define HI3798CV200_FIXED_60M			83
383320f39bSShawn Guo #define HI3798CV200_FIXED_166P5M		84
393320f39bSShawn Guo #define HI3798CV200_SDIO0_MUX			85
4080f8ce58SJianguo Sun #define HI3798CV200_COMBPHY0_MUX		86
41707d33cbSJiancheng Xue 
42707d33cbSJiancheng Xue #define HI3798CV200_CRG_NR_CLKS			128
43707d33cbSJiancheng Xue 
44707d33cbSJiancheng Xue static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = {
45707d33cbSJiancheng Xue 	{ HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, },
46707d33cbSJiancheng Xue 	{ HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, },
47707d33cbSJiancheng Xue 	{ HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, },
480d846596SJiancheng Xue 	{ HI3798CV200_FIXED_12M, "12m", NULL, 0, 12000000, },
49707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, },
50707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, },
510d846596SJiancheng Xue 	{ HI3798CV200_FIXED_48M, "48m", NULL, 0, 48000000, },
52707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, },
530d846596SJiancheng Xue 	{ HI3798CV200_FIXED_60M, "60m", NULL, 0, 60000000, },
54707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, },
55707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, },
56707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, },
573320f39bSShawn Guo 	{ HI3798CV200_FIXED_166P5M, "166p5m", NULL, 0, 165000000, },
58707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, },
59707d33cbSJiancheng Xue 	{ HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, },
60707d33cbSJiancheng Xue };
61707d33cbSJiancheng Xue 
62707d33cbSJiancheng Xue static const char *const mmc_mux_p[] = {
63707d33cbSJiancheng Xue 		"100m", "50m", "25m", "200m", "150m" };
64707d33cbSJiancheng Xue static u32 mmc_mux_table[] = {0, 1, 2, 3, 6};
65707d33cbSJiancheng Xue 
6680f8ce58SJianguo Sun static const char *const comphy_mux_p[] = {
67707d33cbSJiancheng Xue 		"100m", "25m"};
6880f8ce58SJianguo Sun static u32 comphy_mux_table[] = {2, 3};
69707d33cbSJiancheng Xue 
703320f39bSShawn Guo static const char *const sdio_mux_p[] = {
713320f39bSShawn Guo 		"100m", "50m", "150m", "166p5m" };
723320f39bSShawn Guo static u32 sdio_mux_table[] = {0, 1, 2, 3};
733320f39bSShawn Guo 
74707d33cbSJiancheng Xue static struct hisi_mux_clock hi3798cv200_mux_clks[] = {
75707d33cbSJiancheng Xue 	{ HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
76707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, },
7780f8ce58SJianguo Sun 	{ HI3798CV200_COMBPHY0_MUX, "combphy0_mux",
7880f8ce58SJianguo Sun 		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
7980f8ce58SJianguo Sun 		CLK_SET_RATE_PARENT, 0x188, 2, 2, 0, comphy_mux_table, },
80707d33cbSJiancheng Xue 	{ HI3798CV200_COMBPHY1_MUX, "combphy1_mux",
8180f8ce58SJianguo Sun 		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
8280f8ce58SJianguo Sun 		CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy_mux_table, },
833320f39bSShawn Guo 	{ HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p,
843320f39bSShawn Guo 		ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT,
853320f39bSShawn Guo 		0x9c, 8, 2, 0, sdio_mux_table, },
86707d33cbSJiancheng Xue };
87707d33cbSJiancheng Xue 
88d1b03995Stianshuliang static u32 mmc_phase_regvals[] = {0, 1, 2, 3, 4, 5, 6, 7};
89d1b03995Stianshuliang static u32 mmc_phase_degrees[] = {0, 45, 90, 135, 180, 225, 270, 315};
90d1b03995Stianshuliang 
91d1b03995Stianshuliang static struct hisi_phase_clock hi3798cv200_phase_clks[] = {
92d1b03995Stianshuliang 	{ HISTB_MMC_SAMPLE_CLK, "mmc_sample", "clk_mmc_ciu",
93d1b03995Stianshuliang 		CLK_SET_RATE_PARENT, 0xa0, 12, 3, mmc_phase_degrees,
94d1b03995Stianshuliang 		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
95d1b03995Stianshuliang 	{ HISTB_MMC_DRV_CLK, "mmc_drive", "clk_mmc_ciu",
96d1b03995Stianshuliang 		CLK_SET_RATE_PARENT, 0xa0, 16, 3, mmc_phase_degrees,
97d1b03995Stianshuliang 		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
98d1b03995Stianshuliang };
99d1b03995Stianshuliang 
100707d33cbSJiancheng Xue static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
101707d33cbSJiancheng Xue 	/* UART */
102707d33cbSJiancheng Xue 	{ HISTB_UART2_CLK, "clk_uart2", "75m",
103707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x68, 4, 0, },
104707d33cbSJiancheng Xue 	/* I2C */
105707d33cbSJiancheng Xue 	{ HISTB_I2C0_CLK, "clk_i2c0", "clk_apb",
106707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x6C, 4, 0, },
107707d33cbSJiancheng Xue 	{ HISTB_I2C1_CLK, "clk_i2c1", "clk_apb",
108707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x6C, 8, 0, },
109707d33cbSJiancheng Xue 	{ HISTB_I2C2_CLK, "clk_i2c2", "clk_apb",
110707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x6C, 12, 0, },
111707d33cbSJiancheng Xue 	{ HISTB_I2C3_CLK, "clk_i2c3", "clk_apb",
112707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x6C, 16, 0, },
113707d33cbSJiancheng Xue 	{ HISTB_I2C4_CLK, "clk_i2c4", "clk_apb",
114707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x6C, 20, 0, },
115707d33cbSJiancheng Xue 	/* SPI */
116707d33cbSJiancheng Xue 	{ HISTB_SPI0_CLK, "clk_spi0", "clk_apb",
117707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x70, 0, 0, },
118707d33cbSJiancheng Xue 	/* SDIO */
119707d33cbSJiancheng Xue 	{ HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m",
120707d33cbSJiancheng Xue 			CLK_SET_RATE_PARENT, 0x9c, 0, 0, },
1213320f39bSShawn Guo 	{ HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "sdio0_mux",
122707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x9c, 1, 0, },
123707d33cbSJiancheng Xue 	/* EMMC */
124707d33cbSJiancheng Xue 	{ HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m",
125707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
126707d33cbSJiancheng Xue 	{ HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
127707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
128707d33cbSJiancheng Xue 	/* PCIE*/
129707d33cbSJiancheng Xue 	{ HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m",
130707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x18c, 0, 0, },
131707d33cbSJiancheng Xue 	{ HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m",
132707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x18c, 1, 0, },
133707d33cbSJiancheng Xue 	{ HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m",
134707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x18c, 2, 0, },
135707d33cbSJiancheng Xue 	{ HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m",
136707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x18c, 3, 0, },
137707d33cbSJiancheng Xue 	/* Ethernet */
138707d33cbSJiancheng Xue 	{ HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL,
139707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 5, 0, },
140707d33cbSJiancheng Xue 	{ HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub",
141707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 0, 0, },
142707d33cbSJiancheng Xue 	{ HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus",
143707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 1, 0, },
144707d33cbSJiancheng Xue 	{ HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus",
145707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 2, 0, },
146707d33cbSJiancheng Xue 	{ HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0",
147707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 3, 0, },
148707d33cbSJiancheng Xue 	{ HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0",
149707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 24, 0, },
150707d33cbSJiancheng Xue 	{ HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1",
151707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 4, 0, },
152707d33cbSJiancheng Xue 	{ HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1",
153707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0xcc, 25, 0, },
15480f8ce58SJianguo Sun 	/* COMBPHY0 */
15580f8ce58SJianguo Sun 	{ HISTB_COMBPHY0_CLK, "clk_combphy0", "combphy0_mux",
15680f8ce58SJianguo Sun 		CLK_SET_RATE_PARENT, 0x188, 0, 0, },
157707d33cbSJiancheng Xue 	/* COMBPHY1 */
158707d33cbSJiancheng Xue 	{ HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux",
159707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x188, 8, 0, },
1600d846596SJiancheng Xue 	/* USB2 */
1610d846596SJiancheng Xue 	{ HISTB_USB2_BUS_CLK, "clk_u2_bus", "clk_ahb",
1620d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xb8, 0, 0, },
1630d846596SJiancheng Xue 	{ HISTB_USB2_PHY_CLK, "clk_u2_phy", "60m",
1640d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xb8, 4, 0, },
1650d846596SJiancheng Xue 	{ HISTB_USB2_12M_CLK, "clk_u2_12m", "12m",
1660d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xb8, 2, 0 },
1670d846596SJiancheng Xue 	{ HISTB_USB2_48M_CLK, "clk_u2_48m", "48m",
1680d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xb8, 1, 0 },
1690d846596SJiancheng Xue 	{ HISTB_USB2_UTMI_CLK, "clk_u2_utmi", "60m",
1700d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xb8, 5, 0 },
17150fd588aSShawn Guo 	{ HISTB_USB2_OTG_UTMI_CLK, "clk_u2_otg_utmi", "60m",
17250fd588aSShawn Guo 		CLK_SET_RATE_PARENT, 0xb8, 3, 0 },
1730d846596SJiancheng Xue 	{ HISTB_USB2_PHY1_REF_CLK, "clk_u2_phy1_ref", "24m",
1740d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
1750d846596SJiancheng Xue 	{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
1760d846596SJiancheng Xue 		CLK_SET_RATE_PARENT, 0xbc, 2, 0 },
17780820a7bSJianguo Sun 	/* USB3 */
17880820a7bSJianguo Sun 	{ HISTB_USB3_BUS_CLK, "clk_u3_bus", NULL,
17980820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 0, 0 },
18080820a7bSJianguo Sun 	{ HISTB_USB3_UTMI_CLK, "clk_u3_utmi", NULL,
18180820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 4, 0 },
18280820a7bSJianguo Sun 	{ HISTB_USB3_PIPE_CLK, "clk_u3_pipe", NULL,
18380820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 3, 0 },
18480820a7bSJianguo Sun 	{ HISTB_USB3_SUSPEND_CLK, "clk_u3_suspend", NULL,
18580820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 2, 0 },
18680820a7bSJianguo Sun 	{ HISTB_USB3_BUS_CLK1, "clk_u3_bus1", NULL,
18780820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 16, 0 },
18880820a7bSJianguo Sun 	{ HISTB_USB3_UTMI_CLK1, "clk_u3_utmi1", NULL,
18980820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 20, 0 },
19080820a7bSJianguo Sun 	{ HISTB_USB3_PIPE_CLK1, "clk_u3_pipe1", NULL,
19180820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 19, 0 },
19280820a7bSJianguo Sun 	{ HISTB_USB3_SUSPEND_CLK1, "clk_u3_suspend1", NULL,
19380820a7bSJianguo Sun 		CLK_SET_RATE_PARENT, 0xb0, 18, 0 },
194707d33cbSJiancheng Xue };
195707d33cbSJiancheng Xue 
hi3798cv200_clk_register(struct platform_device * pdev)196707d33cbSJiancheng Xue static struct hisi_clock_data *hi3798cv200_clk_register(
197707d33cbSJiancheng Xue 				struct platform_device *pdev)
198707d33cbSJiancheng Xue {
199707d33cbSJiancheng Xue 	struct hisi_clock_data *clk_data;
200707d33cbSJiancheng Xue 	int ret;
201707d33cbSJiancheng Xue 
202707d33cbSJiancheng Xue 	clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS);
203707d33cbSJiancheng Xue 	if (!clk_data)
204707d33cbSJiancheng Xue 		return ERR_PTR(-ENOMEM);
205707d33cbSJiancheng Xue 
206d1b03995Stianshuliang 	/* hisi_phase_clock is resource managed */
207d1b03995Stianshuliang 	ret = hisi_clk_register_phase(&pdev->dev,
208d1b03995Stianshuliang 				hi3798cv200_phase_clks,
209d1b03995Stianshuliang 				ARRAY_SIZE(hi3798cv200_phase_clks),
210d1b03995Stianshuliang 				clk_data);
211d1b03995Stianshuliang 	if (ret)
212d1b03995Stianshuliang 		return ERR_PTR(ret);
213d1b03995Stianshuliang 
214707d33cbSJiancheng Xue 	ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks,
215707d33cbSJiancheng Xue 				     ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
216707d33cbSJiancheng Xue 				     clk_data);
217707d33cbSJiancheng Xue 	if (ret)
218707d33cbSJiancheng Xue 		return ERR_PTR(ret);
219707d33cbSJiancheng Xue 
220707d33cbSJiancheng Xue 	ret = hisi_clk_register_mux(hi3798cv200_mux_clks,
221707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_mux_clks),
222707d33cbSJiancheng Xue 				clk_data);
223707d33cbSJiancheng Xue 	if (ret)
224707d33cbSJiancheng Xue 		goto unregister_fixed_rate;
225707d33cbSJiancheng Xue 
226707d33cbSJiancheng Xue 	ret = hisi_clk_register_gate(hi3798cv200_gate_clks,
227707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_gate_clks),
228707d33cbSJiancheng Xue 				clk_data);
229707d33cbSJiancheng Xue 	if (ret)
230707d33cbSJiancheng Xue 		goto unregister_mux;
231707d33cbSJiancheng Xue 
232707d33cbSJiancheng Xue 	ret = of_clk_add_provider(pdev->dev.of_node,
233707d33cbSJiancheng Xue 			of_clk_src_onecell_get, &clk_data->clk_data);
234707d33cbSJiancheng Xue 	if (ret)
235707d33cbSJiancheng Xue 		goto unregister_gate;
236707d33cbSJiancheng Xue 
237707d33cbSJiancheng Xue 	return clk_data;
238707d33cbSJiancheng Xue 
239055d5689SShawn Guo unregister_gate:
240055d5689SShawn Guo 	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
241055d5689SShawn Guo 				ARRAY_SIZE(hi3798cv200_gate_clks),
242707d33cbSJiancheng Xue 				clk_data);
243707d33cbSJiancheng Xue unregister_mux:
244707d33cbSJiancheng Xue 	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
245707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_mux_clks),
246707d33cbSJiancheng Xue 				clk_data);
247055d5689SShawn Guo unregister_fixed_rate:
248055d5689SShawn Guo 	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
249055d5689SShawn Guo 				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
250707d33cbSJiancheng Xue 				clk_data);
251707d33cbSJiancheng Xue 	return ERR_PTR(ret);
252707d33cbSJiancheng Xue }
253707d33cbSJiancheng Xue 
hi3798cv200_clk_unregister(struct platform_device * pdev)254707d33cbSJiancheng Xue static void hi3798cv200_clk_unregister(struct platform_device *pdev)
255707d33cbSJiancheng Xue {
256707d33cbSJiancheng Xue 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
257707d33cbSJiancheng Xue 
258707d33cbSJiancheng Xue 	of_clk_del_provider(pdev->dev.of_node);
259707d33cbSJiancheng Xue 
260707d33cbSJiancheng Xue 	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
261707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_gate_clks),
262707d33cbSJiancheng Xue 				crg->clk_data);
263707d33cbSJiancheng Xue 	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
264707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_mux_clks),
265707d33cbSJiancheng Xue 				crg->clk_data);
266707d33cbSJiancheng Xue 	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
267707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
268707d33cbSJiancheng Xue 				crg->clk_data);
269707d33cbSJiancheng Xue }
270707d33cbSJiancheng Xue 
271707d33cbSJiancheng Xue static const struct hisi_crg_funcs hi3798cv200_crg_funcs = {
272707d33cbSJiancheng Xue 	.register_clks = hi3798cv200_clk_register,
273707d33cbSJiancheng Xue 	.unregister_clks = hi3798cv200_clk_unregister,
274707d33cbSJiancheng Xue };
275707d33cbSJiancheng Xue 
276707d33cbSJiancheng Xue /* hi3798CV200 sysctrl CRG */
277707d33cbSJiancheng Xue 
278707d33cbSJiancheng Xue #define HI3798CV200_SYSCTRL_NR_CLKS 16
279707d33cbSJiancheng Xue 
280707d33cbSJiancheng Xue static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = {
28147629f67SYounian Wang 	{ HISTB_IR_CLK, "clk_ir", "24m",
282707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x48, 4, 0, },
283707d33cbSJiancheng Xue 	{ HISTB_TIMER01_CLK, "clk_timer01", "24m",
284707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x48, 6, 0, },
285707d33cbSJiancheng Xue 	{ HISTB_UART0_CLK, "clk_uart0", "75m",
286707d33cbSJiancheng Xue 		CLK_SET_RATE_PARENT, 0x48, 10, 0, },
287707d33cbSJiancheng Xue };
288707d33cbSJiancheng Xue 
hi3798cv200_sysctrl_clk_register(struct platform_device * pdev)289707d33cbSJiancheng Xue static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register(
290707d33cbSJiancheng Xue 					struct platform_device *pdev)
291707d33cbSJiancheng Xue {
292707d33cbSJiancheng Xue 	struct hisi_clock_data *clk_data;
293707d33cbSJiancheng Xue 	int ret;
294707d33cbSJiancheng Xue 
295707d33cbSJiancheng Xue 	clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS);
296707d33cbSJiancheng Xue 	if (!clk_data)
297707d33cbSJiancheng Xue 		return ERR_PTR(-ENOMEM);
298707d33cbSJiancheng Xue 
299707d33cbSJiancheng Xue 	ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks,
300707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
301707d33cbSJiancheng Xue 				clk_data);
302707d33cbSJiancheng Xue 	if (ret)
303707d33cbSJiancheng Xue 		return ERR_PTR(ret);
304707d33cbSJiancheng Xue 
305707d33cbSJiancheng Xue 	ret = of_clk_add_provider(pdev->dev.of_node,
306707d33cbSJiancheng Xue 			of_clk_src_onecell_get, &clk_data->clk_data);
307707d33cbSJiancheng Xue 	if (ret)
308707d33cbSJiancheng Xue 		goto unregister_gate;
309707d33cbSJiancheng Xue 
310707d33cbSJiancheng Xue 	return clk_data;
311707d33cbSJiancheng Xue 
312707d33cbSJiancheng Xue unregister_gate:
313707d33cbSJiancheng Xue 	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
314707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
315707d33cbSJiancheng Xue 				clk_data);
316707d33cbSJiancheng Xue 	return ERR_PTR(ret);
317707d33cbSJiancheng Xue }
318707d33cbSJiancheng Xue 
hi3798cv200_sysctrl_clk_unregister(struct platform_device * pdev)319707d33cbSJiancheng Xue static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev)
320707d33cbSJiancheng Xue {
321707d33cbSJiancheng Xue 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
322707d33cbSJiancheng Xue 
323707d33cbSJiancheng Xue 	of_clk_del_provider(pdev->dev.of_node);
324707d33cbSJiancheng Xue 
325707d33cbSJiancheng Xue 	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
326707d33cbSJiancheng Xue 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
327707d33cbSJiancheng Xue 				crg->clk_data);
328707d33cbSJiancheng Xue }
329707d33cbSJiancheng Xue 
330707d33cbSJiancheng Xue static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = {
331707d33cbSJiancheng Xue 	.register_clks = hi3798cv200_sysctrl_clk_register,
332707d33cbSJiancheng Xue 	.unregister_clks = hi3798cv200_sysctrl_clk_unregister,
333707d33cbSJiancheng Xue };
334707d33cbSJiancheng Xue 
335707d33cbSJiancheng Xue static const struct of_device_id hi3798cv200_crg_match_table[] = {
336707d33cbSJiancheng Xue 	{ .compatible = "hisilicon,hi3798cv200-crg",
337707d33cbSJiancheng Xue 		.data = &hi3798cv200_crg_funcs },
338707d33cbSJiancheng Xue 	{ .compatible = "hisilicon,hi3798cv200-sysctrl",
339707d33cbSJiancheng Xue 		.data = &hi3798cv200_sysctrl_funcs },
340707d33cbSJiancheng Xue 	{ }
341707d33cbSJiancheng Xue };
342707d33cbSJiancheng Xue MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table);
343707d33cbSJiancheng Xue 
hi3798cv200_crg_probe(struct platform_device * pdev)344707d33cbSJiancheng Xue static int hi3798cv200_crg_probe(struct platform_device *pdev)
345707d33cbSJiancheng Xue {
346707d33cbSJiancheng Xue 	struct hisi_crg_dev *crg;
347707d33cbSJiancheng Xue 
348707d33cbSJiancheng Xue 	crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
349707d33cbSJiancheng Xue 	if (!crg)
350707d33cbSJiancheng Xue 		return -ENOMEM;
351707d33cbSJiancheng Xue 
352707d33cbSJiancheng Xue 	crg->funcs = of_device_get_match_data(&pdev->dev);
353707d33cbSJiancheng Xue 	if (!crg->funcs)
354707d33cbSJiancheng Xue 		return -ENOENT;
355707d33cbSJiancheng Xue 
356707d33cbSJiancheng Xue 	crg->rstc = hisi_reset_init(pdev);
357707d33cbSJiancheng Xue 	if (!crg->rstc)
358707d33cbSJiancheng Xue 		return -ENOMEM;
359707d33cbSJiancheng Xue 
360707d33cbSJiancheng Xue 	crg->clk_data = crg->funcs->register_clks(pdev);
361707d33cbSJiancheng Xue 	if (IS_ERR(crg->clk_data)) {
362707d33cbSJiancheng Xue 		hisi_reset_exit(crg->rstc);
363707d33cbSJiancheng Xue 		return PTR_ERR(crg->clk_data);
364707d33cbSJiancheng Xue 	}
365707d33cbSJiancheng Xue 
366707d33cbSJiancheng Xue 	platform_set_drvdata(pdev, crg);
367707d33cbSJiancheng Xue 	return 0;
368707d33cbSJiancheng Xue }
369707d33cbSJiancheng Xue 
hi3798cv200_crg_remove(struct platform_device * pdev)370bfa8370bSUwe Kleine-König static void hi3798cv200_crg_remove(struct platform_device *pdev)
371707d33cbSJiancheng Xue {
372707d33cbSJiancheng Xue 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
373707d33cbSJiancheng Xue 
374707d33cbSJiancheng Xue 	hisi_reset_exit(crg->rstc);
375707d33cbSJiancheng Xue 	crg->funcs->unregister_clks(pdev);
376707d33cbSJiancheng Xue }
377707d33cbSJiancheng Xue 
378707d33cbSJiancheng Xue static struct platform_driver hi3798cv200_crg_driver = {
379707d33cbSJiancheng Xue 	.probe          = hi3798cv200_crg_probe,
380bfa8370bSUwe Kleine-König 	.remove_new	= hi3798cv200_crg_remove,
381707d33cbSJiancheng Xue 	.driver         = {
382707d33cbSJiancheng Xue 		.name   = "hi3798cv200-crg",
383707d33cbSJiancheng Xue 		.of_match_table = hi3798cv200_crg_match_table,
384707d33cbSJiancheng Xue 	},
385707d33cbSJiancheng Xue };
386707d33cbSJiancheng Xue 
hi3798cv200_crg_init(void)387707d33cbSJiancheng Xue static int __init hi3798cv200_crg_init(void)
388707d33cbSJiancheng Xue {
389707d33cbSJiancheng Xue 	return platform_driver_register(&hi3798cv200_crg_driver);
390707d33cbSJiancheng Xue }
391707d33cbSJiancheng Xue core_initcall(hi3798cv200_crg_init);
392707d33cbSJiancheng Xue 
hi3798cv200_crg_exit(void)393707d33cbSJiancheng Xue static void __exit hi3798cv200_crg_exit(void)
394707d33cbSJiancheng Xue {
395707d33cbSJiancheng Xue 	platform_driver_unregister(&hi3798cv200_crg_driver);
396707d33cbSJiancheng Xue }
397707d33cbSJiancheng Xue module_exit(hi3798cv200_crg_exit);
398707d33cbSJiancheng Xue 
399707d33cbSJiancheng Xue MODULE_LICENSE("GPL v2");
400707d33cbSJiancheng Xue MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver");
401