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