1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Sophgo SoCs pinctrl common ops.
4  *
5  * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com>
6  *
7  */
8 
9 #include <linux/bsearch.h>
10 #include <linux/cleanup.h>
11 #include <linux/export.h>
12 #include <linux/io.h>
13 #include <linux/of.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/seq_file.h>
17 #include <linux/spinlock.h>
18 
19 #include <linux/pinctrl/pinconf-generic.h>
20 #include <linux/pinctrl/pinctrl.h>
21 
22 #include "../pinctrl-utils.h"
23 #include "../pinconf.h"
24 #include "../pinmux.h"
25 
26 #include "pinctrl-sophgo.h"
27 
28 static u16 sophgo_dt_get_pin(u32 value)
29 {
30 	return value;
31 }
32 
33 static int sophgo_cmp_pin(const void *key, const void *pivot)
34 {
35 	const struct sophgo_pin *pin = pivot;
36 	int pin_id = (long)key;
37 	int pivid = pin->id;
38 
39 	return pin_id - pivid;
40 }
41 
42 const struct sophgo_pin *sophgo_get_pin(struct sophgo_pinctrl *pctrl,
43 					unsigned long pin_id)
44 {
45 	return bsearch((void *)pin_id, pctrl->data->pindata, pctrl->data->npins,
46 		       pctrl->data->pinsize, sophgo_cmp_pin);
47 }
48 
49 static int sophgo_verify_pinmux_config(struct sophgo_pinctrl *pctrl,
50 				       const struct sophgo_pin_mux_config *config)
51 {
52 	if (pctrl->data->cfg_ops->verify_pinmux_config)
53 		return pctrl->data->cfg_ops->verify_pinmux_config(config);
54 	return 0;
55 }
56 
57 static int sophgo_verify_pin_group(struct sophgo_pinctrl *pctrl,
58 				   const struct sophgo_pin_mux_config *config,
59 				   unsigned int npins)
60 {
61 	if (pctrl->data->cfg_ops->verify_pin_group)
62 		return pctrl->data->cfg_ops->verify_pin_group(config, npins);
63 	return 0;
64 }
65 
66 static int sophgo_dt_node_to_map_post(struct device_node *cur,
67 				      struct sophgo_pinctrl *pctrl,
68 				      struct sophgo_pin_mux_config *config,
69 				      unsigned int npins)
70 {
71 	if (pctrl->data->cfg_ops->dt_node_to_map_post)
72 		return pctrl->data->cfg_ops->dt_node_to_map_post(cur, pctrl,
73 								 config, npins);
74 	return 0;
75 }
76 
77 int sophgo_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np,
78 				struct pinctrl_map **maps, unsigned int *num_maps)
79 {
80 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
81 	struct device *dev = pctrl->dev;
82 	struct device_node *child;
83 	struct pinctrl_map *map;
84 	const char **grpnames;
85 	const char *grpname;
86 	int ngroups = 0;
87 	int nmaps = 0;
88 	int ret;
89 
90 	for_each_available_child_of_node(np, child)
91 		ngroups += 1;
92 
93 	grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL);
94 	if (!grpnames)
95 		return -ENOMEM;
96 
97 	map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL);
98 	if (!map)
99 		return -ENOMEM;
100 
101 	ngroups = 0;
102 	guard(mutex)(&pctrl->mutex);
103 	for_each_available_child_of_node(np, child) {
104 		int npins = of_property_count_u32_elems(child, "pinmux");
105 		unsigned int *pins;
106 		struct sophgo_pin_mux_config *pinmuxs;
107 		u32 config;
108 		int i;
109 
110 		if (npins < 1) {
111 			dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n",
112 				np, child);
113 			ret = -EINVAL;
114 			goto dt_failed;
115 		}
116 
117 		grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn",
118 					 np, child);
119 		if (!grpname) {
120 			ret = -ENOMEM;
121 			goto dt_failed;
122 		}
123 
124 		grpnames[ngroups++] = grpname;
125 
126 		pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
127 		if (!pins) {
128 			ret = -ENOMEM;
129 			goto dt_failed;
130 		}
131 
132 		pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL);
133 		if (!pinmuxs) {
134 			ret = -ENOMEM;
135 			goto dt_failed;
136 		}
137 
138 		for (i = 0; i < npins; i++) {
139 			ret = of_property_read_u32_index(child, "pinmux",
140 							 i, &config);
141 			if (ret)
142 				goto dt_failed;
143 
144 			pins[i] = sophgo_dt_get_pin(config);
145 			pinmuxs[i].config = config;
146 			pinmuxs[i].pin = sophgo_get_pin(pctrl, pins[i]);
147 
148 			if (!pinmuxs[i].pin) {
149 				dev_err(dev, "failed to get pin %d\n", pins[i]);
150 				ret = -ENODEV;
151 				goto dt_failed;
152 			}
153 
154 			ret = sophgo_verify_pinmux_config(pctrl, &pinmuxs[i]);
155 			if (ret) {
156 				dev_err(dev, "group %s pin %d is invalid\n",
157 					grpname, i);
158 				goto dt_failed;
159 			}
160 		}
161 
162 		ret = sophgo_verify_pin_group(pctrl, pinmuxs, npins);
163 		if (ret) {
164 			dev_err(dev, "group %s is invalid\n", grpname);
165 			goto dt_failed;
166 		}
167 
168 		ret = sophgo_dt_node_to_map_post(child, pctrl, pinmuxs, npins);
169 		if (ret)
170 			goto dt_failed;
171 
172 		map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
173 		map[nmaps].data.mux.function = np->name;
174 		map[nmaps].data.mux.group = grpname;
175 		nmaps += 1;
176 
177 		ret = pinconf_generic_parse_dt_config(child, pctldev,
178 						      &map[nmaps].data.configs.configs,
179 						      &map[nmaps].data.configs.num_configs);
180 		if (ret) {
181 			dev_err(dev, "failed to parse pin config of group %s: %d\n",
182 				grpname, ret);
183 			goto dt_failed;
184 		}
185 
186 		ret = pinctrl_generic_add_group(pctldev, grpname,
187 						pins, npins, pinmuxs);
188 		if (ret < 0) {
189 			dev_err(dev, "failed to add group %s: %d\n", grpname, ret);
190 			goto dt_failed;
191 		}
192 
193 		/* don't create a map if there are no pinconf settings */
194 		if (map[nmaps].data.configs.num_configs == 0)
195 			continue;
196 
197 		map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
198 		map[nmaps].data.configs.group_or_pin = grpname;
199 		nmaps += 1;
200 	}
201 
202 	ret = pinmux_generic_add_function(pctldev, np->name,
203 					  grpnames, ngroups, NULL);
204 	if (ret < 0) {
205 		dev_err(dev, "error adding function %s: %d\n", np->name, ret);
206 		goto function_failed;
207 	}
208 
209 	*maps = map;
210 	*num_maps = nmaps;
211 
212 	return 0;
213 
214 dt_failed:
215 	of_node_put(child);
216 function_failed:
217 	pinctrl_utils_free_map(pctldev, map, nmaps);
218 	return ret;
219 }
220 
221 int sophgo_pmx_set_mux(struct pinctrl_dev *pctldev,
222 		       unsigned int fsel, unsigned int gsel)
223 {
224 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
225 	const struct group_desc *group;
226 	const struct sophgo_pin_mux_config *configs;
227 	unsigned int i;
228 
229 	group = pinctrl_generic_get_group(pctldev, gsel);
230 	if (!group)
231 		return -EINVAL;
232 
233 	configs = group->data;
234 
235 	for (i = 0; i < group->grp.npins; i++) {
236 		const struct sophgo_pin *pin = configs[i].pin;
237 		u32 value = configs[i].config;
238 
239 		guard(raw_spinlock_irqsave)(&pctrl->lock);
240 
241 		pctrl->data->cfg_ops->set_pinmux_config(pctrl, pin, value);
242 	}
243 
244 	return 0;
245 }
246 
247 static int sophgo_pin_set_config(struct sophgo_pinctrl *pctrl,
248 				 unsigned int pin_id,
249 				 u32 value, u32 mask)
250 {
251 	const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id);
252 
253 	if (!pin)
254 		return -EINVAL;
255 
256 	guard(raw_spinlock_irqsave)(&pctrl->lock);
257 
258 	return pctrl->data->cfg_ops->set_pinconf_config(pctrl, pin, value, mask);
259 }
260 
261 int sophgo_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id,
262 		     unsigned long *configs, unsigned int num_configs)
263 {
264 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
265 	const struct sophgo_pin *pin = sophgo_get_pin(pctrl, pin_id);
266 	u32 value, mask;
267 
268 	if (!pin)
269 		return -ENODEV;
270 
271 	if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pin,
272 							 configs, num_configs,
273 							 &value, &mask))
274 		return -ENOTSUPP;
275 
276 	return sophgo_pin_set_config(pctrl, pin_id, value, mask);
277 }
278 
279 int sophgo_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int gsel,
280 			   unsigned long *configs, unsigned int num_configs)
281 {
282 	struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
283 	const struct group_desc *group;
284 	const struct sophgo_pin_mux_config *pinmuxs;
285 	u32 value, mask;
286 	int i;
287 
288 	group = pinctrl_generic_get_group(pctldev, gsel);
289 	if (!group)
290 		return -EINVAL;
291 
292 	pinmuxs = group->data;
293 
294 	if (pctrl->data->cfg_ops->compute_pinconf_config(pctrl, pinmuxs[0].pin,
295 							 configs, num_configs,
296 							 &value, &mask))
297 		return -ENOTSUPP;
298 
299 	for (i = 0; i < group->grp.npins; i++)
300 		sophgo_pin_set_config(pctrl,  group->grp.pins[i], value, mask);
301 
302 	return 0;
303 }
304 
305 u32 sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl *pctrl,
306 				     const struct sophgo_pin *pin,
307 				     const u32 *power_cfg)
308 {
309 	return pctrl->data->vddio_ops->get_pull_down(pin, power_cfg);
310 }
311 
312 u32 sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl *pctrl,
313 				   const struct sophgo_pin *pin,
314 				   const u32 *power_cfg)
315 {
316 	return pctrl->data->vddio_ops->get_pull_up(pin, power_cfg);
317 }
318 
319 int sophgo_pinctrl_oc2reg(struct sophgo_pinctrl *pctrl,
320 			  const struct sophgo_pin *pin,
321 			  const u32 *power_cfg, u32 target)
322 {
323 	const u32 *map;
324 	int i, len;
325 
326 	if (!pctrl->data->vddio_ops->get_oc_map)
327 		return -ENOTSUPP;
328 
329 	len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map);
330 	if (len < 0)
331 		return len;
332 
333 	for (i = 0; i < len; i++) {
334 		if (map[i] >= target)
335 			return i;
336 	}
337 
338 	return -EINVAL;
339 }
340 
341 int sophgo_pinctrl_reg2oc(struct sophgo_pinctrl *pctrl,
342 			  const struct sophgo_pin *pin,
343 			  const u32 *power_cfg, u32 reg)
344 {
345 	const u32 *map;
346 	int len;
347 
348 	if (!pctrl->data->vddio_ops->get_oc_map)
349 		return -ENOTSUPP;
350 
351 	len = pctrl->data->vddio_ops->get_oc_map(pin, power_cfg, &map);
352 	if (len < 0)
353 		return len;
354 
355 	if (reg >= len)
356 		return -EINVAL;
357 
358 	return map[reg];
359 }
360 
361 int sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl *pctrl,
362 			       const struct sophgo_pin *pin,
363 			       const u32 *power_cfg, u32 target)
364 {
365 	const u32 *map;
366 	int i, len;
367 
368 	if (!pctrl->data->vddio_ops->get_schmitt_map)
369 		return -ENOTSUPP;
370 
371 	len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map);
372 	if (len < 0)
373 		return len;
374 
375 	for (i = 0; i < len; i++) {
376 		if (map[i] == target)
377 			return i;
378 	}
379 
380 	return -EINVAL;
381 }
382 
383 int sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl *pctrl,
384 			       const struct sophgo_pin *pin,
385 			       const u32 *power_cfg, u32 reg)
386 {
387 	const u32 *map;
388 	int len;
389 
390 	if (!pctrl->data->vddio_ops->get_schmitt_map)
391 		return -ENOTSUPP;
392 
393 	len = pctrl->data->vddio_ops->get_schmitt_map(pin, power_cfg, &map);
394 	if (len < 0)
395 		return len;
396 
397 	if (reg >= len)
398 		return -EINVAL;
399 
400 	return map[reg];
401 }
402 
403 int sophgo_pinctrl_probe(struct platform_device *pdev)
404 {
405 	struct device *dev = &pdev->dev;
406 	struct sophgo_pinctrl *pctrl;
407 	const struct sophgo_pinctrl_data *pctrl_data;
408 	int ret;
409 
410 	pctrl_data = device_get_match_data(dev);
411 	if (!pctrl_data)
412 		return -ENODEV;
413 
414 	if (pctrl_data->npins == 0)
415 		return dev_err_probe(dev, -EINVAL, "invalid pin data\n");
416 
417 	pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
418 	if (!pctrl)
419 		return -ENOMEM;
420 
421 	pctrl->pdesc.name = dev_name(dev);
422 	pctrl->pdesc.pins = pctrl_data->pins;
423 	pctrl->pdesc.npins = pctrl_data->npins;
424 	pctrl->pdesc.pctlops = pctrl_data->pctl_ops;
425 	pctrl->pdesc.pmxops = pctrl_data->pmx_ops;
426 	pctrl->pdesc.confops = pctrl_data->pconf_ops;
427 	pctrl->pdesc.owner = THIS_MODULE;
428 
429 	pctrl->data = pctrl_data;
430 	pctrl->dev = dev;
431 	raw_spin_lock_init(&pctrl->lock);
432 	mutex_init(&pctrl->mutex);
433 
434 	ret = pctrl->data->cfg_ops->pctrl_init(pdev, pctrl);
435 	if (ret)
436 		return ret;
437 
438 	platform_set_drvdata(pdev, pctrl);
439 
440 	ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc,
441 					     pctrl, &pctrl->pctrl_dev);
442 	if (ret)
443 		return dev_err_probe(dev, ret,
444 				     "fail to register pinctrl driver\n");
445 
446 	return pinctrl_enable(pctrl->pctrl_dev);
447 }
448 EXPORT_SYMBOL_GPL(sophgo_pinctrl_probe);
449 
450 MODULE_DESCRIPTION("Common pinctrl helper function for the Sophgo SoC");
451 MODULE_LICENSE("GPL");
452