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
sophgo_dt_get_pin(u32 value)28 static u16 sophgo_dt_get_pin(u32 value)
29 {
30 return value;
31 }
32
sophgo_cmp_pin(const void * key,const void * pivot)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
sophgo_get_pin(struct sophgo_pinctrl * pctrl,unsigned long pin_id)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
sophgo_verify_pinmux_config(struct sophgo_pinctrl * pctrl,const struct sophgo_pin_mux_config * config)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
sophgo_verify_pin_group(struct sophgo_pinctrl * pctrl,const struct sophgo_pin_mux_config * config,unsigned int npins)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
sophgo_dt_node_to_map_post(struct device_node * cur,struct sophgo_pinctrl * pctrl,struct sophgo_pin_mux_config * config,unsigned int npins)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
sophgo_pctrl_dt_node_to_map(struct pinctrl_dev * pctldev,struct device_node * np,struct pinctrl_map ** maps,unsigned int * num_maps)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
sophgo_pmx_set_mux(struct pinctrl_dev * pctldev,unsigned int fsel,unsigned int gsel)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
sophgo_pin_set_config(struct sophgo_pinctrl * pctrl,unsigned int pin_id,u32 value,u32 mask)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
sophgo_pconf_set(struct pinctrl_dev * pctldev,unsigned int pin_id,unsigned long * configs,unsigned int num_configs)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
sophgo_pconf_group_set(struct pinctrl_dev * pctldev,unsigned int gsel,unsigned long * configs,unsigned int num_configs)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
sophgo_pinctrl_typical_pull_down(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg)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
sophgo_pinctrl_typical_pull_up(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg)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
sophgo_pinctrl_oc2reg(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg,u32 target)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
sophgo_pinctrl_reg2oc(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg,u32 reg)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
sophgo_pinctrl_schmitt2reg(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg,u32 target)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
sophgo_pinctrl_reg2schmitt(struct sophgo_pinctrl * pctrl,const struct sophgo_pin * pin,const u32 * power_cfg,u32 reg)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
sophgo_pinctrl_probe(struct platform_device * pdev)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