1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Sophgo CV18XX SoCs pinctrl driver.
4  *
5  * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com>
6  *
7  */
8 
9 #include <linux/bitfield.h>
10 #include <linux/export.h>
11 #include <linux/io.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/bsearch.h>
15 #include <linux/seq_file.h>
16 #include <linux/spinlock.h>
17 
18 #include <linux/pinctrl/pinconf-generic.h>
19 #include <linux/pinctrl/pinconf.h>
20 #include <linux/pinctrl/pinctrl.h>
21 #include <linux/pinctrl/pinmux.h>
22 
23 #include <dt-bindings/pinctrl/pinctrl-cv18xx.h>
24 
25 #include "../pinctrl-utils.h"
26 #include "../pinmux.h"
27 #include "pinctrl-cv18xx.h"
28 
29 struct cv1800_priv {
30 	u32					*power_cfg;
31 	void __iomem				*regs[2];
32 };
33 
cv1800_dt_get_pin_mux(u32 value)34 static unsigned int cv1800_dt_get_pin_mux(u32 value)
35 {
36 	return (value >> 16) & GENMASK(7, 0);
37 }
38 
cv1800_dt_get_pin_mux2(u32 value)39 static unsigned int cv1800_dt_get_pin_mux2(u32 value)
40 {
41 	return (value >> 24) & GENMASK(7, 0);
42 }
43 
44 #define cv1800_pinctrl_get_component_addr(pctrl, _comp)		\
45 	((pctrl)->regs[(_comp)->area] + (_comp)->offset)
46 
cv1800_set_power_cfg(struct sophgo_pinctrl * pctrl,u8 domain,u32 cfg)47 static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl,
48 				u8 domain, u32 cfg)
49 {
50 	struct cv1800_priv *priv = pctrl->priv_ctrl;
51 
52 	if (domain >= pctrl->data->npds)
53 		return -ENOTSUPP;
54 
55 	if (priv->power_cfg[domain] && priv->power_cfg[domain] != cfg)
56 		return -EINVAL;
57 
58 	priv->power_cfg[domain] = cfg;
59 
60 	return 0;
61 }
62 
cv1800_get_power_cfg(struct sophgo_pinctrl * pctrl,u8 domain)63 static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl,
64 				u8 domain)
65 {
66 	struct cv1800_priv *priv = pctrl->priv_ctrl;
67 
68 	return priv->power_cfg[domain];
69 }
70 
71 #define PIN_BGA_ID_OFFSET		8
72 #define PIN_BGA_ID_MASK			0xff
73 
74 static const char *const io_type_desc[] = {
75 	"1V8",
76 	"18OD33",
77 	"AUDIO",
78 	"ETH"
79 };
80 
cv1800_get_power_cfg_desc(struct sophgo_pinctrl * pctrl,u8 domain)81 static const char *cv1800_get_power_cfg_desc(struct sophgo_pinctrl *pctrl,
82 					     u8 domain)
83 {
84 	return pctrl->data->pdnames[domain];
85 }
86 
cv1800_pctrl_dbg_show(struct pinctrl_dev * pctldev,struct seq_file * seq,unsigned int pin_id)87 static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev,
88 				  struct seq_file *seq, unsigned int pin_id)
89 {
90 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
91 	struct cv1800_priv *priv = pctrl->priv_ctrl;
92 	const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id);
93 	const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp);
94 	enum cv1800_pin_io_type type = cv1800_pin_io_type(pin);
95 	u32 pin_hwid = pin->pin.id;
96 	u32 value;
97 	void __iomem *reg;
98 
99 	if (pin_hwid >> PIN_BGA_ID_OFFSET)
100 		seq_printf(seq, "pos: %c%u ",
101 			   'A' + (pin_hwid >> PIN_BGA_ID_OFFSET) - 1,
102 			   pin_hwid & PIN_BGA_ID_MASK);
103 	else
104 		seq_printf(seq, "pos: %u ", pin_hwid);
105 
106 	seq_printf(seq, "power-domain: %s ",
107 		   cv1800_get_power_cfg_desc(pctrl, pin->power_domain));
108 	seq_printf(seq, "type: %s ", io_type_desc[type]);
109 
110 	reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux);
111 	value = readl(reg);
112 	seq_printf(seq, "mux: 0x%08x ", value);
113 
114 	if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) {
115 		reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux2);
116 		value = readl(reg);
117 		seq_printf(seq, "mux2: 0x%08x ", value);
118 	}
119 
120 	if (type == IO_TYPE_1V8_ONLY || type == IO_TYPE_1V8_OR_3V3) {
121 		reg = cv1800_pinctrl_get_component_addr(priv, &pin->conf);
122 		value = readl(reg);
123 		seq_printf(seq, "conf: 0x%08x ", value);
124 	}
125 }
126 
cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config * config)127 static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *config)
128 {
129 	struct cv1800_pin *pin = sophgo_to_cv1800_pin(config->pin);
130 	unsigned int mux = cv1800_dt_get_pin_mux(config->config);
131 	unsigned int mux2 = cv1800_dt_get_pin_mux2(config->config);
132 
133 	if (mux > pin->mux.max)
134 		return -EINVAL;
135 
136 	if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) {
137 		if (mux != pin->mux2.pfunc)
138 			return -EINVAL;
139 
140 		if (mux2 > pin->mux2.max)
141 			return -EINVAL;
142 	} else {
143 		if (mux2 != PIN_MUX_INVALD)
144 			return -ENOTSUPP;
145 	}
146 
147 	return 0;
148 }
149 
cv1800_verify_pin_group(const struct sophgo_pin_mux_config * mux,unsigned int npins)150 static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux,
151 				   unsigned int npins)
152 {
153 	struct cv1800_pin *pin;
154 	enum cv1800_pin_io_type type;
155 	u8 power_domain;
156 	int i;
157 
158 	if (npins == 1)
159 		return 0;
160 
161 	pin = sophgo_to_cv1800_pin(mux[0].pin);
162 	type = cv1800_pin_io_type(pin);
163 	power_domain = pin->power_domain;
164 
165 	for (i = 0; i < npins; i++) {
166 		pin = sophgo_to_cv1800_pin(mux[i].pin);
167 
168 		if (type != cv1800_pin_io_type(pin) ||
169 		    power_domain != pin->power_domain)
170 			return -ENOTSUPP;
171 	}
172 
173 	return 0;
174 }
175 
cv1800_dt_node_to_map_post(struct device_node * cur,struct sophgo_pinctrl * pctrl,struct sophgo_pin_mux_config * pinmuxs,unsigned int npins)176 static int cv1800_dt_node_to_map_post(struct device_node *cur,
177 				      struct sophgo_pinctrl *pctrl,
178 				      struct sophgo_pin_mux_config *pinmuxs,
179 				      unsigned int npins)
180 {
181 	const struct cv1800_pin *pin = sophgo_to_cv1800_pin(pinmuxs[0].pin);
182 	u32 power;
183 	int ret;
184 
185 	ret = of_property_read_u32(cur, "power-source", &power);
186 	if (ret)
187 		return ret;
188 
189 	if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8))
190 		return -ENOTSUPP;
191 
192 	return cv1800_set_power_cfg(pctrl, pin->power_domain, power);
193 }
194 
195 const struct pinctrl_ops cv1800_pctrl_ops = {
196 	.get_groups_count	= pinctrl_generic_get_group_count,
197 	.get_group_name		= pinctrl_generic_get_group_name,
198 	.get_group_pins		= pinctrl_generic_get_group_pins,
199 	.pin_dbg_show		= cv1800_pctrl_dbg_show,
200 	.dt_node_to_map		= sophgo_pctrl_dt_node_to_map,
201 	.dt_free_map		= pinctrl_utils_free_map,
202 };
203 EXPORT_SYMBOL_GPL(cv1800_pctrl_ops);
204 
cv1800_set_pinmux_config(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * sp,u32 config)205 static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl,
206 				     const struct sophgo_pin *sp, u32 config)
207 {
208 	const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp);
209 	struct cv1800_priv *priv = pctrl->priv_ctrl;
210 	void __iomem *reg_mux;
211 	void __iomem *reg_mux2;
212 	u32 mux;
213 	u32 mux2;
214 
215 	reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux);
216 	reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2);
217 	mux = cv1800_dt_get_pin_mux(config);
218 	mux2 = cv1800_dt_get_pin_mux2(config);
219 
220 	writel_relaxed(mux, reg_mux);
221 	if (mux2 != PIN_MUX_INVALD)
222 		writel_relaxed(mux2, reg_mux2);
223 }
224 
225 const struct pinmux_ops cv1800_pmx_ops = {
226 	.get_functions_count	= pinmux_generic_get_function_count,
227 	.get_function_name	= pinmux_generic_get_function_name,
228 	.get_function_groups	= pinmux_generic_get_function_groups,
229 	.set_mux		= sophgo_pmx_set_mux,
230 	.strict			= true,
231 };
232 EXPORT_SYMBOL_GPL(cv1800_pmx_ops);
233 
234 #define PIN_IO_PULLUP		BIT(2)
235 #define PIN_IO_PULLDOWN		BIT(3)
236 #define PIN_IO_DRIVE		GENMASK(7, 5)
237 #define PIN_IO_SCHMITT		GENMASK(9, 8)
238 #define PIN_IO_BUS_HOLD		BIT(10)
239 #define PIN_IO_OUT_FAST_SLEW	BIT(11)
240 
cv1800_pconf_get(struct pinctrl_dev * pctldev,unsigned int pin_id,unsigned long * config)241 static int cv1800_pconf_get(struct pinctrl_dev *pctldev,
242 			    unsigned int pin_id, unsigned long *config)
243 {
244 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
245 	struct cv1800_priv *priv = pctrl->priv_ctrl;
246 	int param = pinconf_to_config_param(*config);
247 	const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id);
248 	const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp);
249 	enum cv1800_pin_io_type type;
250 	u32 value;
251 	u32 arg;
252 	bool enabled;
253 	int ret;
254 
255 	if (!pin)
256 		return -EINVAL;
257 
258 	type = cv1800_pin_io_type(pin);
259 	if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO)
260 		return -ENOTSUPP;
261 
262 	value = readl(cv1800_pinctrl_get_component_addr(priv, &pin->conf));
263 
264 	switch (param) {
265 	case PIN_CONFIG_BIAS_PULL_DOWN:
266 		enabled = FIELD_GET(PIN_IO_PULLDOWN, value);
267 		arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, priv->power_cfg);
268 		break;
269 	case PIN_CONFIG_BIAS_PULL_UP:
270 		enabled = FIELD_GET(PIN_IO_PULLUP, value);
271 		arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, priv->power_cfg);
272 		break;
273 	case PIN_CONFIG_DRIVE_STRENGTH_UA:
274 		enabled = true;
275 		arg = FIELD_GET(PIN_IO_DRIVE, value);
276 		ret = sophgo_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg);
277 		if (ret < 0)
278 			return ret;
279 		arg = ret;
280 		break;
281 	case PIN_CONFIG_INPUT_SCHMITT_UV:
282 		arg = FIELD_GET(PIN_IO_SCHMITT, value);
283 		ret = sophgo_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg);
284 		if (ret < 0)
285 			return ret;
286 		arg = ret;
287 		enabled = arg != 0;
288 		break;
289 	case PIN_CONFIG_POWER_SOURCE:
290 		enabled = true;
291 		arg = cv1800_get_power_cfg(pctrl, pin->power_domain);
292 		break;
293 	case PIN_CONFIG_SLEW_RATE:
294 		enabled = true;
295 		arg = FIELD_GET(PIN_IO_OUT_FAST_SLEW, value);
296 		break;
297 	case PIN_CONFIG_BIAS_BUS_HOLD:
298 		arg = FIELD_GET(PIN_IO_BUS_HOLD, value);
299 		enabled = arg != 0;
300 		break;
301 	default:
302 		return -ENOTSUPP;
303 	}
304 
305 	*config = pinconf_to_config_packed(param, arg);
306 
307 	return enabled ? 0 : -EINVAL;
308 }
309 
cv1800_pinconf_compute_config(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * sp,unsigned long * configs,unsigned int num_configs,u32 * value,u32 * mask)310 static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl,
311 					 const struct sophgo_pin *sp,
312 					 unsigned long *configs,
313 					 unsigned int num_configs,
314 					 u32 *value, u32 *mask)
315 {
316 	struct cv1800_priv *priv = pctrl->priv_ctrl;
317 	const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp);
318 	int i;
319 	u32 v = 0, m = 0;
320 	enum cv1800_pin_io_type type;
321 	int ret;
322 
323 	if (!pin)
324 		return -EINVAL;
325 
326 	type = cv1800_pin_io_type(pin);
327 	if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO)
328 		return -ENOTSUPP;
329 
330 	for (i = 0; i < num_configs; i++) {
331 		int param = pinconf_to_config_param(configs[i]);
332 		u32 arg = pinconf_to_config_argument(configs[i]);
333 
334 		switch (param) {
335 		case PIN_CONFIG_BIAS_PULL_DOWN:
336 			v &= ~PIN_IO_PULLDOWN;
337 			v |= FIELD_PREP(PIN_IO_PULLDOWN, arg);
338 			m |= PIN_IO_PULLDOWN;
339 			break;
340 		case PIN_CONFIG_BIAS_PULL_UP:
341 			v &= ~PIN_IO_PULLUP;
342 			v |= FIELD_PREP(PIN_IO_PULLUP, arg);
343 			m |= PIN_IO_PULLUP;
344 			break;
345 		case PIN_CONFIG_DRIVE_STRENGTH_UA:
346 			ret = sophgo_pinctrl_oc2reg(pctrl, sp,
347 						    priv->power_cfg, arg);
348 			if (ret < 0)
349 				return ret;
350 			v &= ~PIN_IO_DRIVE;
351 			v |= FIELD_PREP(PIN_IO_DRIVE, ret);
352 			m |= PIN_IO_DRIVE;
353 			break;
354 		case PIN_CONFIG_INPUT_SCHMITT_UV:
355 			ret = sophgo_pinctrl_schmitt2reg(pctrl, sp,
356 							 priv->power_cfg, arg);
357 			if (ret < 0)
358 				return ret;
359 			v &= ~PIN_IO_SCHMITT;
360 			v |= FIELD_PREP(PIN_IO_SCHMITT, ret);
361 			m |= PIN_IO_SCHMITT;
362 			break;
363 		case PIN_CONFIG_POWER_SOURCE:
364 			/* Ignore power source as it is always fixed */
365 			break;
366 		case PIN_CONFIG_SLEW_RATE:
367 			v &= ~PIN_IO_OUT_FAST_SLEW;
368 			v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg);
369 			m |= PIN_IO_OUT_FAST_SLEW;
370 			break;
371 		case PIN_CONFIG_BIAS_BUS_HOLD:
372 			v &= ~PIN_IO_BUS_HOLD;
373 			v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg);
374 			m |= PIN_IO_BUS_HOLD;
375 			break;
376 		default:
377 			return -ENOTSUPP;
378 		}
379 	}
380 
381 	*value = v;
382 	*mask = m;
383 
384 	return 0;
385 }
386 
cv1800_set_pinconf_config(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * sp,u32 value,u32 mask)387 static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl,
388 				     const struct sophgo_pin *sp,
389 				     u32 value, u32 mask)
390 {
391 	struct cv1800_priv *priv = pctrl->priv_ctrl;
392 	struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp);
393 	void __iomem *addr;
394 	u32 reg;
395 
396 	addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf);
397 
398 	reg = readl(addr);
399 	reg &= ~mask;
400 	reg |= value;
401 	writel(reg, addr);
402 
403 	return 0;
404 }
405 
406 const struct pinconf_ops cv1800_pconf_ops = {
407 	.pin_config_get			= cv1800_pconf_get,
408 	.pin_config_set			= sophgo_pconf_set,
409 	.pin_config_group_set		= sophgo_pconf_group_set,
410 	.is_generic			= true,
411 };
412 EXPORT_SYMBOL_GPL(cv1800_pconf_ops);
413 
cv1800_pinctrl_init(struct platform_device * pdev,struct sophgo_pinctrl * pctrl)414 static int cv1800_pinctrl_init(struct platform_device *pdev,
415 			       struct sophgo_pinctrl *pctrl)
416 {
417 	const struct sophgo_pinctrl_data *pctrl_data = pctrl->data;
418 	struct cv1800_priv *priv;
419 
420 	priv = devm_kzalloc(&pdev->dev, sizeof(struct cv1800_priv), GFP_KERNEL);
421 	if (!priv)
422 		return -ENOMEM;
423 
424 	priv->power_cfg = devm_kcalloc(&pdev->dev, pctrl_data->npds,
425 				       sizeof(u32), GFP_KERNEL);
426 	if (!priv->power_cfg)
427 		return -ENOMEM;
428 
429 	priv->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys");
430 	if (IS_ERR(priv->regs[0]))
431 		return PTR_ERR(priv->regs[0]);
432 
433 	priv->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc");
434 	if (IS_ERR(priv->regs[1]))
435 		return PTR_ERR(priv->regs[1]);
436 
437 	pctrl->priv_ctrl = priv;
438 
439 	return 0;
440 }
441 
442 const struct sophgo_cfg_ops cv1800_cfg_ops = {
443 	.pctrl_init = cv1800_pinctrl_init,
444 	.verify_pinmux_config = cv1800_verify_pinmux_config,
445 	.verify_pin_group = cv1800_verify_pin_group,
446 	.dt_node_to_map_post = cv1800_dt_node_to_map_post,
447 	.compute_pinconf_config = cv1800_pinconf_compute_config,
448 	.set_pinconf_config = cv1800_set_pinconf_config,
449 	.set_pinmux_config = cv1800_set_pinmux_config,
450 };
451 EXPORT_SYMBOL_GPL(cv1800_cfg_ops);
452