xref: /linux/drivers/clk/eswin/clk-eic7700-hsp.c (revision 502d45774af09f1c681c754c4b7cdfb5d7f72fd9)
1*8d92085fSXuyang Dong // SPDX-License-Identifier: GPL-2.0
2*8d92085fSXuyang Dong /*
3*8d92085fSXuyang Dong  * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
4*8d92085fSXuyang Dong  * All rights reserved.
5*8d92085fSXuyang Dong  *
6*8d92085fSXuyang Dong  * ESWIN EIC7700 HSP Clock Driver
7*8d92085fSXuyang Dong  *
8*8d92085fSXuyang Dong  * Authors: Xuyang Dong <dongxuyang@eswincomputing.com>
9*8d92085fSXuyang Dong  */
10*8d92085fSXuyang Dong 
11*8d92085fSXuyang Dong #include <linux/auxiliary_bus.h>
12*8d92085fSXuyang Dong #include <linux/clk-provider.h>
13*8d92085fSXuyang Dong #include <linux/platform_device.h>
14*8d92085fSXuyang Dong #include <linux/regmap.h>
15*8d92085fSXuyang Dong 
16*8d92085fSXuyang Dong #include <dt-bindings/clock/eswin,eic7700-hspcrg.h>
17*8d92085fSXuyang Dong 
18*8d92085fSXuyang Dong #include "common.h"
19*8d92085fSXuyang Dong 
20*8d92085fSXuyang Dong #define EIC7700_HSP_SATA_REG		0x300
21*8d92085fSXuyang Dong #define EIC7700_HSP_MSHC0_REG		0x510
22*8d92085fSXuyang Dong #define EIC7700_HSP_MSHC1_REG		0x610
23*8d92085fSXuyang Dong #define EIC7700_HSP_MSHC2_REG		0x710
24*8d92085fSXuyang Dong #define EIC7700_HSP_USB0_REG		0x800
25*8d92085fSXuyang Dong #define EIC7700_HSP_USB0_REF_REG	0x83c
26*8d92085fSXuyang Dong #define EIC7700_HSP_USB1_REG		0x900
27*8d92085fSXuyang Dong #define EIC7700_HSP_USB1_REF_REG	0x93c
28*8d92085fSXuyang Dong 
29*8d92085fSXuyang Dong #define USB_REF_XTAL24M			0x2a
30*8d92085fSXuyang Dong #define EIC7700_HSP_NR_CLKS		(EIC7700_HSP_CLK_GATE_SATA + 1)
31*8d92085fSXuyang Dong 
32*8d92085fSXuyang Dong struct eic7700_hsp_clk_gate {
33*8d92085fSXuyang Dong 	struct clk_hw hw;
34*8d92085fSXuyang Dong 	unsigned int id;
35*8d92085fSXuyang Dong 	struct regmap *regmap;
36*8d92085fSXuyang Dong 	unsigned int reg;
37*8d92085fSXuyang Dong 	unsigned int ref_reg;
38*8d92085fSXuyang Dong 	const char *name;
39*8d92085fSXuyang Dong 	const struct clk_parent_data *parent_data;
40*8d92085fSXuyang Dong 	unsigned long flags;
41*8d92085fSXuyang Dong 	unsigned int offset;
42*8d92085fSXuyang Dong 	unsigned int ref_offset;
43*8d92085fSXuyang Dong 	u8 bit_idx;
44*8d92085fSXuyang Dong };
45*8d92085fSXuyang Dong 
46*8d92085fSXuyang Dong static const struct regmap_config eic7700_hsp_regmap_config = {
47*8d92085fSXuyang Dong 	.reg_bits = 32,
48*8d92085fSXuyang Dong 	.val_bits = 32,
49*8d92085fSXuyang Dong 	.max_register = 0x1ffc,
50*8d92085fSXuyang Dong 	.reg_stride = 4,
51*8d92085fSXuyang Dong 	.fast_io = true,
52*8d92085fSXuyang Dong 	.use_raw_spinlock = true,
53*8d92085fSXuyang Dong };
54*8d92085fSXuyang Dong 
to_gate_clk(struct clk_hw * hw)55*8d92085fSXuyang Dong static inline struct eic7700_hsp_clk_gate *to_gate_clk(struct clk_hw *hw)
56*8d92085fSXuyang Dong {
57*8d92085fSXuyang Dong 	return container_of(hw, struct eic7700_hsp_clk_gate, hw);
58*8d92085fSXuyang Dong }
59*8d92085fSXuyang Dong 
60*8d92085fSXuyang Dong #define EIC7700_HSP_GATE(_id, _name, _pdata, _flags, _offset, _idx,	\
61*8d92085fSXuyang Dong 			 _ref_offset)					\
62*8d92085fSXuyang Dong 	{								\
63*8d92085fSXuyang Dong 		.id		= _id,					\
64*8d92085fSXuyang Dong 		.name		= _name,				\
65*8d92085fSXuyang Dong 		.parent_data	= _pdata,				\
66*8d92085fSXuyang Dong 		.flags		= _flags,				\
67*8d92085fSXuyang Dong 		.offset		= _offset,				\
68*8d92085fSXuyang Dong 		.ref_offset	= _ref_offset,				\
69*8d92085fSXuyang Dong 		.bit_idx	= _idx,					\
70*8d92085fSXuyang Dong 	}
71*8d92085fSXuyang Dong 
hsp_clk_gate_endisable(struct clk_hw * hw,bool enable)72*8d92085fSXuyang Dong static void hsp_clk_gate_endisable(struct clk_hw *hw, bool enable)
73*8d92085fSXuyang Dong {
74*8d92085fSXuyang Dong 	struct eic7700_hsp_clk_gate *gate = to_gate_clk(hw);
75*8d92085fSXuyang Dong 
76*8d92085fSXuyang Dong 	if (enable) {
77*8d92085fSXuyang Dong 		/*
78*8d92085fSXuyang Dong 		 * Hardware bug: The USB reference clock must be 24MHz.
79*8d92085fSXuyang Dong 		 * The default register value after reset is invalid.
80*8d92085fSXuyang Dong 		 * Workaround: Rewrite the correct value before enabling
81*8d92085fSXuyang Dong 		 * the USB gate clock.
82*8d92085fSXuyang Dong 		 */
83*8d92085fSXuyang Dong 		regmap_update_bits(gate->regmap, gate->ref_reg, 0x3f,
84*8d92085fSXuyang Dong 				   USB_REF_XTAL24M);
85*8d92085fSXuyang Dong 	}
86*8d92085fSXuyang Dong 	regmap_assign_bits(gate->regmap, gate->reg, BIT(gate->bit_idx), enable);
87*8d92085fSXuyang Dong }
88*8d92085fSXuyang Dong 
hsp_clk_gate_enable(struct clk_hw * hw)89*8d92085fSXuyang Dong static int hsp_clk_gate_enable(struct clk_hw *hw)
90*8d92085fSXuyang Dong {
91*8d92085fSXuyang Dong 	hsp_clk_gate_endisable(hw, true);
92*8d92085fSXuyang Dong 
93*8d92085fSXuyang Dong 	return 0;
94*8d92085fSXuyang Dong }
95*8d92085fSXuyang Dong 
hsp_clk_gate_disable(struct clk_hw * hw)96*8d92085fSXuyang Dong static void hsp_clk_gate_disable(struct clk_hw *hw)
97*8d92085fSXuyang Dong {
98*8d92085fSXuyang Dong 	hsp_clk_gate_endisable(hw, false);
99*8d92085fSXuyang Dong }
100*8d92085fSXuyang Dong 
hsp_clk_gate_is_enabled(struct clk_hw * hw)101*8d92085fSXuyang Dong static int hsp_clk_gate_is_enabled(struct clk_hw *hw)
102*8d92085fSXuyang Dong {
103*8d92085fSXuyang Dong 	struct eic7700_hsp_clk_gate *gate = to_gate_clk(hw);
104*8d92085fSXuyang Dong 	unsigned int val;
105*8d92085fSXuyang Dong 	int ret;
106*8d92085fSXuyang Dong 
107*8d92085fSXuyang Dong 	ret = regmap_read(gate->regmap, gate->reg, &val);
108*8d92085fSXuyang Dong 	if (ret != 0)
109*8d92085fSXuyang Dong 		return ret;
110*8d92085fSXuyang Dong 
111*8d92085fSXuyang Dong 	return !!(val & BIT(gate->bit_idx));
112*8d92085fSXuyang Dong }
113*8d92085fSXuyang Dong 
114*8d92085fSXuyang Dong static const struct clk_ops hsp_clk_gate_ops = {
115*8d92085fSXuyang Dong 	.enable = hsp_clk_gate_enable,
116*8d92085fSXuyang Dong 	.disable = hsp_clk_gate_disable,
117*8d92085fSXuyang Dong 	.is_enabled = hsp_clk_gate_is_enabled,
118*8d92085fSXuyang Dong };
119*8d92085fSXuyang Dong 
120*8d92085fSXuyang Dong static struct clk_hw *
hsp_clk_register_gate(struct device * dev,unsigned int id,const char * name,const struct clk_parent_data * parent_data,unsigned long flags,struct regmap * regmap,unsigned int reg,unsigned int ref_reg,u8 bit_idx)121*8d92085fSXuyang Dong hsp_clk_register_gate(struct device *dev, unsigned int id, const char *name,
122*8d92085fSXuyang Dong 		      const struct clk_parent_data *parent_data,
123*8d92085fSXuyang Dong 		      unsigned long flags, struct regmap *regmap,
124*8d92085fSXuyang Dong 		      unsigned int reg, unsigned int ref_reg, u8 bit_idx)
125*8d92085fSXuyang Dong {
126*8d92085fSXuyang Dong 	struct eic7700_hsp_clk_gate *gate;
127*8d92085fSXuyang Dong 	struct clk_init_data init = {};
128*8d92085fSXuyang Dong 	struct clk_hw *hw;
129*8d92085fSXuyang Dong 	int ret;
130*8d92085fSXuyang Dong 
131*8d92085fSXuyang Dong 	gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
132*8d92085fSXuyang Dong 	if (!gate)
133*8d92085fSXuyang Dong 		return ERR_PTR(-ENOMEM);
134*8d92085fSXuyang Dong 
135*8d92085fSXuyang Dong 	init.name = name;
136*8d92085fSXuyang Dong 	init.ops = &hsp_clk_gate_ops;
137*8d92085fSXuyang Dong 	init.flags = flags;
138*8d92085fSXuyang Dong 	init.parent_data = parent_data;
139*8d92085fSXuyang Dong 	init.num_parents = 1;
140*8d92085fSXuyang Dong 
141*8d92085fSXuyang Dong 	gate->id = id;
142*8d92085fSXuyang Dong 	gate->regmap = regmap;
143*8d92085fSXuyang Dong 	gate->reg = reg;
144*8d92085fSXuyang Dong 	gate->ref_reg = ref_reg;
145*8d92085fSXuyang Dong 	gate->bit_idx = bit_idx;
146*8d92085fSXuyang Dong 	gate->hw.init = &init;
147*8d92085fSXuyang Dong 
148*8d92085fSXuyang Dong 	hw = &gate->hw;
149*8d92085fSXuyang Dong 	ret = devm_clk_hw_register(dev, hw);
150*8d92085fSXuyang Dong 	if (ret)
151*8d92085fSXuyang Dong 		hw = ERR_PTR(ret);
152*8d92085fSXuyang Dong 
153*8d92085fSXuyang Dong 	return hw;
154*8d92085fSXuyang Dong }
155*8d92085fSXuyang Dong 
156*8d92085fSXuyang Dong static const struct clk_parent_data hsp_cfg[] = {
157*8d92085fSXuyang Dong 	{ .index = 0 }
158*8d92085fSXuyang Dong };
159*8d92085fSXuyang Dong 
160*8d92085fSXuyang Dong static const struct clk_parent_data hsp_mmc[] = {
161*8d92085fSXuyang Dong 	{ .index = 1 }
162*8d92085fSXuyang Dong };
163*8d92085fSXuyang Dong 
164*8d92085fSXuyang Dong static const struct clk_parent_data hsp_usb_sata[] = {
165*8d92085fSXuyang Dong 	{ .index = 2 }
166*8d92085fSXuyang Dong };
167*8d92085fSXuyang Dong 
168*8d92085fSXuyang Dong static struct eswin_fixed_factor_clock eic7700_hsp_factor_clks[] = {
169*8d92085fSXuyang Dong 	ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_CFG_DIV2, "factor_hsp_cfg_div2",
170*8d92085fSXuyang Dong 		     hsp_cfg, 1, 2, 0),
171*8d92085fSXuyang Dong 	ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_CFG_DIV4, "factor_hsp_cfg_div4",
172*8d92085fSXuyang Dong 		     hsp_cfg, 1, 4, 0),
173*8d92085fSXuyang Dong 	ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_MMC_DIV10, "factor_hsp_mmc_div10",
174*8d92085fSXuyang Dong 		     hsp_mmc, 1, 10, 0),
175*8d92085fSXuyang Dong };
176*8d92085fSXuyang Dong 
177*8d92085fSXuyang Dong static struct eswin_gate_clock eic7700_hsp_gate_clks[] = {
178*8d92085fSXuyang Dong 	ESWIN_GATE(EIC7700_HSP_CLK_GATE_SATA, "gate_clk_hsp_sata", hsp_usb_sata,
179*8d92085fSXuyang Dong 		   CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
180*8d92085fSXuyang Dong 		   EIC7700_HSP_SATA_REG, 28, 0),
181*8d92085fSXuyang Dong 	ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC0_TMR, "gate_clk_hsp_mshc0_tmr",
182*8d92085fSXuyang Dong 		   hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
183*8d92085fSXuyang Dong 		   EIC7700_HSP_MSHC0_REG, 8, 0),
184*8d92085fSXuyang Dong 	ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC1_TMR, "gate_clk_hsp_mshc1_tmr",
185*8d92085fSXuyang Dong 		   hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
186*8d92085fSXuyang Dong 		   EIC7700_HSP_MSHC1_REG, 8, 0),
187*8d92085fSXuyang Dong 	ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC2_TMR, "gate_clk_hsp_mshc2_tmr",
188*8d92085fSXuyang Dong 		   hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
189*8d92085fSXuyang Dong 		   EIC7700_HSP_MSHC2_REG, 8, 0),
190*8d92085fSXuyang Dong };
191*8d92085fSXuyang Dong 
192*8d92085fSXuyang Dong static struct eic7700_hsp_clk_gate eic7700_hsp_spec_gate_clks[] = {
193*8d92085fSXuyang Dong 	EIC7700_HSP_GATE(EIC7700_HSP_CLK_GATE_USB0, "gate_clk_hsp_usb0",
194*8d92085fSXuyang Dong 			 hsp_usb_sata, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
195*8d92085fSXuyang Dong 			 EIC7700_HSP_USB0_REG, 28, EIC7700_HSP_USB0_REF_REG),
196*8d92085fSXuyang Dong 	EIC7700_HSP_GATE(EIC7700_HSP_CLK_GATE_USB1, "gate_clk_hsp_usb1",
197*8d92085fSXuyang Dong 			 hsp_usb_sata, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
198*8d92085fSXuyang Dong 			 EIC7700_HSP_USB1_REG, 28, EIC7700_HSP_USB1_REF_REG),
199*8d92085fSXuyang Dong };
200*8d92085fSXuyang Dong 
201*8d92085fSXuyang Dong static const struct clk_parent_data mux_mmc_3mux1_p[] = {
202*8d92085fSXuyang Dong 	{ .fw_name = "cfg" },
203*8d92085fSXuyang Dong 	{ .hw = &eic7700_hsp_factor_clks[0].hw },
204*8d92085fSXuyang Dong 	{ .hw = &eic7700_hsp_factor_clks[1].hw },
205*8d92085fSXuyang Dong };
206*8d92085fSXuyang Dong 
207*8d92085fSXuyang Dong static const struct clk_parent_data mux_mmc_2mux1_p[] = {
208*8d92085fSXuyang Dong 	{ .fw_name = "mmc" },
209*8d92085fSXuyang Dong 	{ .hw = &eic7700_hsp_factor_clks[2].hw },
210*8d92085fSXuyang Dong };
211*8d92085fSXuyang Dong 
212*8d92085fSXuyang Dong static u32 mux_mmc_3mux1_tbl[] = { 0x0, 0x1, 0x3 };
213*8d92085fSXuyang Dong 
214*8d92085fSXuyang Dong static struct eswin_mux_clock eic7700_hsp_mux_clks[] = {
215*8d92085fSXuyang Dong 	ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_EMMC_3MUX1, "mux_hsp_emmc_3mux1",
216*8d92085fSXuyang Dong 		      mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
217*8d92085fSXuyang Dong 		      CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC0_REG, 16, 2, 0,
218*8d92085fSXuyang Dong 		      mux_mmc_3mux1_tbl),
219*8d92085fSXuyang Dong 	ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_SD0_3MUX1, "mux_hsp_sd0_3mux1",
220*8d92085fSXuyang Dong 		      mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
221*8d92085fSXuyang Dong 		      CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC1_REG, 16, 2, 0,
222*8d92085fSXuyang Dong 		      mux_mmc_3mux1_tbl),
223*8d92085fSXuyang Dong 	ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_SD1_3MUX1, "mux_hsp_sd1_3mux1",
224*8d92085fSXuyang Dong 		      mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
225*8d92085fSXuyang Dong 		      CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC2_REG, 16, 2, 0,
226*8d92085fSXuyang Dong 		      mux_mmc_3mux1_tbl),
227*8d92085fSXuyang Dong 	ESWIN_MUX(EIC7700_HSP_CLK_MUX_EMMC_CQE_2MUX1, "mux_hsp_emmc_cqe_2mux1",
228*8d92085fSXuyang Dong 		  mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
229*8d92085fSXuyang Dong 		  CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC0_REG, 0, 1, 0),
230*8d92085fSXuyang Dong 	ESWIN_MUX(EIC7700_HSP_CLK_MUX_SD0_CQE_2MUX1, "mux_hsp_sd0_cqe_2mux1",
231*8d92085fSXuyang Dong 		  mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
232*8d92085fSXuyang Dong 		  CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC1_REG, 0, 1, 0),
233*8d92085fSXuyang Dong 	ESWIN_MUX(EIC7700_HSP_CLK_MUX_SD1_CQE_2MUX1, "mux_hsp_sd1_cqe_2mux1",
234*8d92085fSXuyang Dong 		  mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
235*8d92085fSXuyang Dong 		  CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC2_REG, 0, 1, 0),
236*8d92085fSXuyang Dong };
237*8d92085fSXuyang Dong 
238*8d92085fSXuyang Dong static struct eswin_clk_info eic7700_hsp_clks[] = {
239*8d92085fSXuyang Dong 	ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_EMMC, "gate_clk_hsp_emmc",
240*8d92085fSXuyang Dong 			EIC7700_HSP_CLK_MUX_EMMC_3MUX1,
241*8d92085fSXuyang Dong 			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
242*8d92085fSXuyang Dong 			EIC7700_HSP_MSHC0_REG, 24, 0),
243*8d92085fSXuyang Dong 	ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_SD0, "gate_clk_hsp_sd0",
244*8d92085fSXuyang Dong 			EIC7700_HSP_CLK_MUX_SD0_3MUX1,
245*8d92085fSXuyang Dong 			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
246*8d92085fSXuyang Dong 			EIC7700_HSP_MSHC1_REG, 24, 0),
247*8d92085fSXuyang Dong 	ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_SD1, "gate_clk_hsp_sd1",
248*8d92085fSXuyang Dong 			EIC7700_HSP_CLK_MUX_SD1_3MUX1,
249*8d92085fSXuyang Dong 			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
250*8d92085fSXuyang Dong 			EIC7700_HSP_MSHC2_REG, 24, 0),
251*8d92085fSXuyang Dong };
252*8d92085fSXuyang Dong 
eic7700_hsp_clk_probe(struct platform_device * pdev)253*8d92085fSXuyang Dong static int eic7700_hsp_clk_probe(struct platform_device *pdev)
254*8d92085fSXuyang Dong {
255*8d92085fSXuyang Dong 	struct device *dev = &pdev->dev;
256*8d92085fSXuyang Dong 	struct auxiliary_device *adev;
257*8d92085fSXuyang Dong 	struct eswin_clock_data *data;
258*8d92085fSXuyang Dong 	struct regmap *regmap;
259*8d92085fSXuyang Dong 	struct clk_hw *hw;
260*8d92085fSXuyang Dong 	int i, ret;
261*8d92085fSXuyang Dong 
262*8d92085fSXuyang Dong 	data = eswin_clk_init(pdev, EIC7700_HSP_NR_CLKS);
263*8d92085fSXuyang Dong 	if (IS_ERR(data))
264*8d92085fSXuyang Dong 		return dev_err_probe(dev, PTR_ERR(data),
265*8d92085fSXuyang Dong 				     "failed to get clk data!\n");
266*8d92085fSXuyang Dong 
267*8d92085fSXuyang Dong 	regmap = devm_regmap_init_mmio(dev, data->base,
268*8d92085fSXuyang Dong 				       &eic7700_hsp_regmap_config);
269*8d92085fSXuyang Dong 	if (IS_ERR(regmap))
270*8d92085fSXuyang Dong 		return dev_err_probe(dev, PTR_ERR(regmap),
271*8d92085fSXuyang Dong 				     "failed to get regmap!\n");
272*8d92085fSXuyang Dong 
273*8d92085fSXuyang Dong 	ret = eswin_clk_register_fixed_factor(dev, eic7700_hsp_factor_clks,
274*8d92085fSXuyang Dong 					      ARRAY_SIZE(eic7700_hsp_factor_clks),
275*8d92085fSXuyang Dong 					      data);
276*8d92085fSXuyang Dong 	if (ret)
277*8d92085fSXuyang Dong 		return dev_err_probe(dev, ret,
278*8d92085fSXuyang Dong 				     "failed to register fixed factor clock\n");
279*8d92085fSXuyang Dong 
280*8d92085fSXuyang Dong 	ret = eswin_clk_register_gate(dev, eic7700_hsp_gate_clks,
281*8d92085fSXuyang Dong 				      ARRAY_SIZE(eic7700_hsp_gate_clks), data);
282*8d92085fSXuyang Dong 	if (ret)
283*8d92085fSXuyang Dong 		return dev_err_probe(dev, ret,
284*8d92085fSXuyang Dong 				     "failed to register gate clock\n");
285*8d92085fSXuyang Dong 
286*8d92085fSXuyang Dong 	ret = eswin_clk_register_mux(dev, eic7700_hsp_mux_clks,
287*8d92085fSXuyang Dong 				     ARRAY_SIZE(eic7700_hsp_mux_clks),
288*8d92085fSXuyang Dong 				     data);
289*8d92085fSXuyang Dong 	if (ret)
290*8d92085fSXuyang Dong 		return dev_err_probe(dev, ret,
291*8d92085fSXuyang Dong 				     "failed to register mux clock\n");
292*8d92085fSXuyang Dong 
293*8d92085fSXuyang Dong 	ret = eswin_clk_register_clks(dev, eic7700_hsp_clks,
294*8d92085fSXuyang Dong 				      ARRAY_SIZE(eic7700_hsp_clks), data);
295*8d92085fSXuyang Dong 	if (ret)
296*8d92085fSXuyang Dong 		return dev_err_probe(dev, ret,
297*8d92085fSXuyang Dong 				     "failed to register clock\n");
298*8d92085fSXuyang Dong 
299*8d92085fSXuyang Dong 	for (i = 0; i < ARRAY_SIZE(eic7700_hsp_spec_gate_clks); i++) {
300*8d92085fSXuyang Dong 		struct eic7700_hsp_clk_gate *gate;
301*8d92085fSXuyang Dong 
302*8d92085fSXuyang Dong 		gate = &eic7700_hsp_spec_gate_clks[i];
303*8d92085fSXuyang Dong 		hw = hsp_clk_register_gate(dev, gate->id, gate->name,
304*8d92085fSXuyang Dong 					   gate->parent_data, gate->flags,
305*8d92085fSXuyang Dong 					   regmap, gate->offset,
306*8d92085fSXuyang Dong 					   gate->ref_offset, gate->bit_idx);
307*8d92085fSXuyang Dong 		if (IS_ERR(hw))
308*8d92085fSXuyang Dong 			return dev_err_probe(dev, PTR_ERR(hw),
309*8d92085fSXuyang Dong 					     "failed to register gate clock\n");
310*8d92085fSXuyang Dong 
311*8d92085fSXuyang Dong 		data->clk_data.hws[gate->id] = hw;
312*8d92085fSXuyang Dong 	}
313*8d92085fSXuyang Dong 
314*8d92085fSXuyang Dong 	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
315*8d92085fSXuyang Dong 					  &data->clk_data);
316*8d92085fSXuyang Dong 	if (ret)
317*8d92085fSXuyang Dong 		return dev_err_probe(dev, ret, "add clk provider failed\n");
318*8d92085fSXuyang Dong 
319*8d92085fSXuyang Dong 	adev = devm_auxiliary_device_create(dev, "hsp-reset", NULL);
320*8d92085fSXuyang Dong 	if (!adev)
321*8d92085fSXuyang Dong 		return dev_err_probe(dev, -ENODEV,
322*8d92085fSXuyang Dong 				     "register hsp-reset device failed\n");
323*8d92085fSXuyang Dong 
324*8d92085fSXuyang Dong 	return 0;
325*8d92085fSXuyang Dong }
326*8d92085fSXuyang Dong 
327*8d92085fSXuyang Dong static const struct of_device_id eic7700_hsp_clock_dt_ids[] = {
328*8d92085fSXuyang Dong 	{ .compatible = "eswin,eic7700-hspcrg", },
329*8d92085fSXuyang Dong 	{ /* sentinel */ }
330*8d92085fSXuyang Dong };
331*8d92085fSXuyang Dong MODULE_DEVICE_TABLE(of, eic7700_hsp_clock_dt_ids);
332*8d92085fSXuyang Dong 
333*8d92085fSXuyang Dong static struct platform_driver eic7700_hsp_clock_driver = {
334*8d92085fSXuyang Dong 	.probe	= eic7700_hsp_clk_probe,
335*8d92085fSXuyang Dong 	.driver = {
336*8d92085fSXuyang Dong 		.name	= "eic7700-hsp-clock",
337*8d92085fSXuyang Dong 		.of_match_table	= eic7700_hsp_clock_dt_ids,
338*8d92085fSXuyang Dong 	},
339*8d92085fSXuyang Dong };
340*8d92085fSXuyang Dong 
341*8d92085fSXuyang Dong module_platform_driver(eic7700_hsp_clock_driver);
342*8d92085fSXuyang Dong 
343*8d92085fSXuyang Dong MODULE_LICENSE("GPL");
344*8d92085fSXuyang Dong MODULE_AUTHOR("Xuyang Dong <dongxuyang@eswincomputing.com>");
345*8d92085fSXuyang Dong MODULE_DESCRIPTION("ESWIN EIC7700 HSP clock controller driver");
346