File Index
Files and directories
Sign in
FILE

pinctrl-sky1-base.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pinctrl/cix/pinctrl-sky1-base.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2//
  3// Author: Jerry Zhu <Jerry.Zhu@cixtech.com>
  4// Author: Gary Yang <gary.yang@cixtech.com>
  5
  6#include <linux/device.h>
  7#include <linux/err.h>
  8#include <linux/init.h>
  9#include <linux/io.h>
 10#include <linux/module.h>
 11#include <linux/of.h>
 12#include <linux/of_device.h>
 13#include <linux/of_address.h>
 14#include <linux/pinctrl/pinconf.h>
 15#include <linux/pinctrl/pinconf-generic.h>
 16#include <linux/pinctrl/pinctrl.h>
 17#include <linux/pinctrl/pinmux.h>
 18#include <linux/platform_device.h>
 19#include <linux/seq_file.h>
 20#include <linux/slab.h>
 21
 22#include "../core.h"
 23#include "../pinconf.h"
 24#include "../pinctrl-utils.h"
 25#include "../pinmux.h"
 26#include "pinctrl-sky1.h"
 27
 28#define SKY1_PIN_SIZE		(4)
 29#define SKY1_MUX_MASK		GENMASK(8, 7)
 30#define SKY1_MUX_SHIFT		(7)
 31#define SKY1_PULLCONF_MASK	GENMASK(6, 5)
 32#define SKY1_PULLUP_BIT		(6)
 33#define SKY1_PULLDN_BIT		(5)
 34#define SKY1_DS_MASK		GENMASK(3, 0)
 35
 36#define CIX_PIN_NO_SHIFT	(8)
 37#define CIX_PIN_FUN_MASK	GENMASK(1, 0)
 38#define CIX_GET_PIN_NO(x)	((x) >> CIX_PIN_NO_SHIFT)
 39#define CIX_GET_PIN_FUNC(x)	((x) & CIX_PIN_FUN_MASK)
 40#define SKY1_DEFAULT_DS_VAL	(4)
 41
 42static const char * const sky1_gpio_functions[] = {
 43	"func0", "func1", "func2", "func3",
 44};
 45
 46static unsigned char sky1_ds_table[] = {
 47	2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 17, 18, 20, 21, 23, 24,
 48};
 49
 50static bool sky1_pctrl_is_function_valid(struct sky1_pinctrl *spctl,
 51		u32 pin_num, u32 fnum)
 52{
 53	int i;
 54
 55	for (i = 0; i < spctl->info->npins; i++) {
 56		const struct sky1_pin_desc *pin = spctl->info->pins + i;
 57
 58		if (pin->pin.number == pin_num) {
 59			if (fnum < pin->nfunc)
 60				return true;
 61
 62			break;
 63		}
 64	}
 65
 66	return false;
 67}
 68
 69static int sky1_pctrl_dt_node_to_map_func(struct sky1_pinctrl *spctl,
 70		u32 pin, u32 fnum, struct sky1_pinctrl_group *grp,
 71		struct pinctrl_map **map, unsigned int *reserved_maps,
 72		unsigned int *num_maps)
 73{
 74	bool ret;
 75
 76	if (*num_maps == *reserved_maps)
 77		return -ENOSPC;
 78
 79	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
 80	(*map)[*num_maps].data.mux.group = grp->name;
 81
 82	ret = sky1_pctrl_is_function_valid(spctl, pin, fnum);
 83	if (!ret) {
 84		dev_err(spctl->dev, "invalid function %d on pin %d .\n",
 85				fnum, pin);
 86		return -EINVAL;
 87	}
 88
 89	(*map)[*num_maps].data.mux.function = sky1_gpio_functions[fnum];
 90	(*num_maps)++;
 91
 92	return 0;
 93}
 94
 95static struct sky1_pinctrl_group *
 96sky1_pctrl_find_group_by_pin(struct sky1_pinctrl *spctl, u32 pin)
 97{
 98	int i;
 99
100	for (i = 0; i < spctl->info->npins; i++) {
101		struct sky1_pinctrl_group *grp =
102			(struct sky1_pinctrl_group *)spctl->groups + i;
103
104		if (grp->pin == pin)
105			return grp;
106	}
107
108	return NULL;
109}
110
111static int sky1_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
112				      struct device_node *node,
113				      struct pinctrl_map **map,
114				      unsigned int *reserved_maps,
115				      unsigned int *num_maps)
116{
117	struct property *pins;
118	u32 pinfunc, pin, func;
119	int num_pins, num_funcs, maps_per_pin;
120	unsigned long *configs;
121	unsigned int num_configs;
122	bool has_config = false;
123	int i, err;
124	unsigned int reserve = 0;
125	struct sky1_pinctrl_group *grp;
126	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
127
128	pins = of_find_property(node, "pinmux", NULL);
129	if (!pins) {
130		dev_err(spctl->dev, "missing pins property in node %pOFn .\n",
131				node);
132		return -EINVAL;
133	}
134
135	err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
136		&num_configs);
137	if (err)
138		return err;
139
140	if (num_configs)
141		has_config = true;
142
143	num_pins = pins->length / sizeof(u32);
144	num_funcs = num_pins;
145	maps_per_pin = 0;
146	if (num_funcs)
147		maps_per_pin++;
148	if (has_config && num_pins >= 1)
149		maps_per_pin++;
150
151	if (!num_pins || !maps_per_pin) {
152		err = -EINVAL;
153		goto exit;
154	}
155
156	reserve = num_pins * maps_per_pin;
157
158	err = pinctrl_utils_reserve_map(pctldev, map,
159			reserved_maps, num_maps, reserve);
160	if (err < 0)
161		goto exit;
162
163	for (i = 0; i < num_pins; i++) {
164		err = of_property_read_u32_index(node, "pinmux",
165				i, &pinfunc);
166		if (err)
167			goto exit;
168
169		pin = CIX_GET_PIN_NO(pinfunc);
170		func = CIX_GET_PIN_FUNC(pinfunc);
171		pctldev->num_functions = ARRAY_SIZE(sky1_gpio_functions);
172
173		if (pin >= pctldev->desc->npins ||
174			func >= pctldev->num_functions) {
175			dev_err(spctl->dev, "invalid pins value.\n");
176			err = -EINVAL;
177			goto exit;
178		}
179
180		grp = sky1_pctrl_find_group_by_pin(spctl, pin);
181		if (!grp) {
182			dev_err(spctl->dev, "unable to match pin %d to group\n",
183					pin);
184			err = -EINVAL;
185			goto exit;
186		}
187
188		err = sky1_pctrl_dt_node_to_map_func(spctl, pin, func, grp,
189				map, reserved_maps, num_maps);
190		if (err < 0)
191			goto exit;
192
193		if (has_config) {
194			err = pinctrl_utils_add_map_configs(pctldev, map,
195					reserved_maps, num_maps, grp->name,
196					configs, num_configs,
197					PIN_MAP_TYPE_CONFIGS_GROUP);
198			if (err < 0)
199				goto exit;
200		}
201	}
202
203	err = 0;
204
205exit:
206	kfree(configs);
207	return err;
208}
209
210static int sky1_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
211				 struct device_node *np_config,
212				 struct pinctrl_map **map, unsigned int *num_maps)
213{
214	unsigned int reserved_maps;
215	int ret;
216
217	*map = NULL;
218	*num_maps = 0;
219	reserved_maps = 0;
220
221	for_each_child_of_node_scoped(np_config, np) {
222		ret = sky1_pctrl_dt_subnode_to_map(pctldev, np, map,
223				&reserved_maps, num_maps);
224		if (ret < 0) {
225			pinctrl_utils_free_map(pctldev, *map, *num_maps);
226			return ret;
227		}
228	}
229
230	return 0;
231}
232
233static void sky1_dt_free_map(struct pinctrl_dev *pctldev,
234			     struct pinctrl_map *map,
235			     unsigned int num_maps)
236{
237	kfree(map);
238}
239
240static int sky1_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
241{
242	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
243
244	return spctl->info->npins;
245}
246
247static const char *sky1_pctrl_get_group_name(struct pinctrl_dev *pctldev,
248					      unsigned int group)
249{
250	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
251
252	return spctl->groups[group].name;
253}
254
255static int sky1_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
256				      unsigned int group,
257				      const unsigned int **pins,
258				      unsigned int *num_pins)
259{
260	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
261
262	*pins = (unsigned int *)&spctl->groups[group].pin;
263	*num_pins = 1;
264
265	return 0;
266}
267
268static void sky1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
269		   unsigned int offset)
270{
271	seq_printf(s, "%s", dev_name(pctldev->dev));
272}
273
274static const struct pinctrl_ops sky1_pctrl_ops = {
275	.dt_node_to_map = sky1_pctrl_dt_node_to_map,
276	.dt_free_map = sky1_dt_free_map,
277	.get_groups_count = sky1_pctrl_get_groups_count,
278	.get_group_name = sky1_pctrl_get_group_name,
279	.get_group_pins = sky1_pctrl_get_group_pins,
280	.pin_dbg_show = sky1_pin_dbg_show,
281};
282
283static int sky1_pmx_set_one_pin(struct sky1_pinctrl *spctl,
284				    unsigned int pin, unsigned char muxval)
285{
286	u32 reg_val;
287	void __iomem *pin_reg;
288
289	pin_reg = spctl->base + pin * SKY1_PIN_SIZE;
290	reg_val = readl(pin_reg);
291	reg_val &= ~SKY1_MUX_MASK;
292	reg_val |= muxval << SKY1_MUX_SHIFT;
293	writel(reg_val, pin_reg);
294
295	dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n",
296		pin * SKY1_PIN_SIZE, reg_val);
297	return 0;
298}
299
300static int sky1_pmx_set_mux(struct pinctrl_dev *pctldev,
301			    unsigned int function,
302			    unsigned int group)
303{
304	bool ret;
305	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
306	struct sky1_pinctrl_group *g =
307		(struct sky1_pinctrl_group *)spctl->groups + group;
308
309	ret = sky1_pctrl_is_function_valid(spctl, g->pin, function);
310	if (!ret) {
311		dev_err(spctl->dev, "invalid function %d on group %d .\n",
312				function, group);
313		return -EINVAL;
314	}
315
316	sky1_pmx_set_one_pin(spctl, g->pin, function);
317	return 0;
318}
319
320static int sky1_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
321{
322	return ARRAY_SIZE(sky1_gpio_functions);
323}
324
325static const char *sky1_pmx_get_func_name(struct pinctrl_dev *pctldev,
326					   unsigned int selector)
327{
328	return sky1_gpio_functions[selector];
329}
330
331static int sky1_pmx_get_func_groups(struct pinctrl_dev *pctldev,
332				     unsigned int function,
333				     const char * const **groups,
334				     unsigned int * const num_groups)
335{
336	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
337	const struct sky1_pinctrl_soc_info *info = spctl->info;
338
339	*groups = spctl->grp_names;
340	*num_groups = info->npins;
341
342	return 0;
343}
344
345static const struct pinmux_ops sky1_pmx_ops = {
346	.get_functions_count = sky1_pmx_get_funcs_cnt,
347	.get_function_groups = sky1_pmx_get_func_groups,
348	.get_function_name = sky1_pmx_get_func_name,
349	.set_mux = sky1_pmx_set_mux,
350};
351
352static int sky1_pconf_set_pull_select(struct sky1_pinctrl *spctl,
353		unsigned int pin, bool enable, bool isup)
354{
355	u32 reg_val, reg_pullsel = 0;
356	void __iomem *pin_reg;
357
358	pin_reg = spctl->base + pin * SKY1_PIN_SIZE;
359	reg_val = readl(pin_reg);
360	reg_val &= ~SKY1_PULLCONF_MASK;
361
362	if (!enable)
363		goto update;
364
365	if (isup)
366		reg_pullsel = BIT(SKY1_PULLUP_BIT);
367	else
368		reg_pullsel = BIT(SKY1_PULLDN_BIT);
369
370update:
371	reg_val |= reg_pullsel;
372	writel(reg_val, pin_reg);
373
374	dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n",
375		pin * SKY1_PIN_SIZE, reg_val);
376	return 0;
377}
378
379static int sky1_ds_to_index(unsigned char driving)
380{
381	int i;
382
383	for (i = 0; i < sizeof(sky1_ds_table); i++)
384		if (driving == sky1_ds_table[i])
385			return i;
386	return SKY1_DEFAULT_DS_VAL;
387}
388
389static int sky1_pconf_set_driving(struct sky1_pinctrl *spctl,
390		unsigned int pin, unsigned char driving)
391{
392	unsigned int reg_val, val;
393	void __iomem *pin_reg;
394
395	if (pin >= spctl->info->npins)
396		return -EINVAL;
397
398	pin_reg = spctl->base + pin * SKY1_PIN_SIZE;
399	reg_val = readl(pin_reg);
400	reg_val &= ~SKY1_DS_MASK;
401	val = sky1_ds_to_index(driving);
402	reg_val |= (val & SKY1_DS_MASK);
403	writel(reg_val, pin_reg);
404
405	dev_dbg(spctl->dev, "write: offset 0x%x val 0x%x\n",
406		pin * SKY1_PIN_SIZE, reg_val);
407
408	return 0;
409}
410
411static int sky1_pconf_parse_conf(struct pinctrl_dev *pctldev,
412		unsigned int pin, enum pin_config_param param,
413		enum pin_config_param arg)
414{
415	int ret = 0;
416	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
417
418	switch (param) {
419	case PIN_CONFIG_BIAS_DISABLE:
420		ret = sky1_pconf_set_pull_select(spctl, pin, false, false);
421		break;
422	case PIN_CONFIG_BIAS_PULL_UP:
423		ret = sky1_pconf_set_pull_select(spctl, pin, true, true);
424		break;
425	case PIN_CONFIG_BIAS_PULL_DOWN:
426		ret = sky1_pconf_set_pull_select(spctl, pin, true, false);
427		break;
428	case PIN_CONFIG_DRIVE_STRENGTH:
429		ret = sky1_pconf_set_driving(spctl, pin, arg);
430		break;
431	default:
432		ret = -EINVAL;
433	}
434
435	return ret;
436}
437
438static int sky1_pconf_group_get(struct pinctrl_dev *pctldev,
439				 unsigned int group,
440				 unsigned long *config)
441{
442	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
443	struct sky1_pinctrl_group *g = &spctl->groups[group];
444
445	*config = g->config;
446
447	return 0;
448}
449
450static int sky1_pconf_group_set(struct pinctrl_dev *pctldev, unsigned int group,
451				 unsigned long *configs, unsigned int num_configs)
452{
453	struct sky1_pinctrl *spctl = pinctrl_dev_get_drvdata(pctldev);
454	struct sky1_pinctrl_group *g = &spctl->groups[group];
455	int i, ret;
456
457	for (i = 0; i < num_configs; i++) {
458		ret = sky1_pconf_parse_conf(pctldev, g->pin,
459			pinconf_to_config_param(configs[i]),
460			pinconf_to_config_argument(configs[i]));
461		if (ret < 0)
462			return ret;
463
464		g->config = configs[i];
465	}
466
467	return 0;
468}
469
470static const struct pinconf_ops sky1_pinconf_ops = {
471	.pin_config_group_get	= sky1_pconf_group_get,
472	.pin_config_group_set	= sky1_pconf_group_set,
473};
474
475static int sky1_pctrl_build_state(struct platform_device *pdev)
476{
477	struct sky1_pinctrl *spctl = platform_get_drvdata(pdev);
478	const struct sky1_pinctrl_soc_info *info = spctl->info;
479	int i;
480
481	/* Allocate groups */
482	spctl->groups = devm_kcalloc(&pdev->dev, info->npins,
483				    sizeof(*spctl->groups), GFP_KERNEL);
484	if (!spctl->groups)
485		return -ENOMEM;
486
487	/* We assume that one pin is one group, use pin name as group name. */
488	spctl->grp_names = devm_kcalloc(&pdev->dev, info->npins,
489				       sizeof(*spctl->grp_names), GFP_KERNEL);
490	if (!spctl->grp_names)
491		return -ENOMEM;
492
493	for (i = 0; i < info->npins; i++) {
494		const struct sky1_pin_desc *pin = spctl->info->pins + i;
495		struct sky1_pinctrl_group *group =
496			(struct sky1_pinctrl_group *)spctl->groups + i;
497
498		group->name = pin->pin.name;
499		group->pin = pin->pin.number;
500		spctl->grp_names[i] = pin->pin.name;
501	}
502
503	return 0;
504}
505
506int sky1_base_pinctrl_probe(struct platform_device *pdev,
507		      const struct sky1_pinctrl_soc_info *info)
508{
509	struct pinctrl_desc *sky1_pinctrl_desc;
510	struct sky1_pinctrl *spctl;
511	struct pinctrl_pin_desc *pins;
512	int ret, i;
513
514	if (!info || !info->pins || !info->npins) {
515		dev_err(&pdev->dev, "wrong pinctrl info\n");
516		return -EINVAL;
517	}
518
519	/* Create state holders etc for this driver */
520	spctl = devm_kzalloc(&pdev->dev, sizeof(*spctl), GFP_KERNEL);
521	if (!spctl)
522		return -ENOMEM;
523
524	spctl->info = info;
525	platform_set_drvdata(pdev, spctl);
526
527	spctl->base = devm_platform_ioremap_resource(pdev, 0);
528	if (IS_ERR(spctl->base))
529		return PTR_ERR(spctl->base);
530
531	sky1_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*sky1_pinctrl_desc),
532					GFP_KERNEL);
533	if (!sky1_pinctrl_desc)
534		return -ENOMEM;
535
536	pins = devm_kcalloc(&pdev->dev, info->npins, sizeof(*pins),
537			    GFP_KERNEL);
538	if (!pins)
539		return -ENOMEM;
540	for (i = 0; i < info->npins; i++)
541		pins[i] = info->pins[i].pin;
542
543	ret = sky1_pctrl_build_state(pdev);
544	if (ret)
545		return ret;
546
547	sky1_pinctrl_desc->name = dev_name(&pdev->dev);
548	sky1_pinctrl_desc->pins = pins;
549	sky1_pinctrl_desc->npins = info->npins;
550	sky1_pinctrl_desc->pctlops = &sky1_pctrl_ops;
551	sky1_pinctrl_desc->pmxops = &sky1_pmx_ops;
552	sky1_pinctrl_desc->confops = &sky1_pinconf_ops;
553	sky1_pinctrl_desc->owner = THIS_MODULE;
554	spctl->dev = &pdev->dev;
555	ret = devm_pinctrl_register_and_init(&pdev->dev,
556					     sky1_pinctrl_desc, spctl,
557					     &spctl->pctl);
558	if (ret) {
559		dev_err(&pdev->dev, "could not register SKY1 pinctrl driver\n");
560		return ret;
561	}
562
563	/*
564	 * The SKY1 SoC has two pin controllers: one for normal working state
565	 * and one for sleep state. Since one controller only has working
566	 * states and the other only sleep states, it will seem to the
567	 * controller is always in the first configured state, so no
568	 * transitions between default->sleep->default are detected and no
569	 * new pin states are applied when we go in and out of sleep state.
570	 *
571	 * To counter this, provide dummies, so that the sleep-only pin
572	 * controller still get some default states, and the working state pin
573	 * controller get some sleep states, so that state transitions occur
574	 * and we re-configure pins for default and sleep states.
575	 */
576	pinctrl_provide_dummies();
577
578	dev_dbg(&pdev->dev, "initialized SKY1 pinctrl driver\n");
579
580	return pinctrl_enable(spctl->pctl);
581}
582EXPORT_SYMBOL_GPL(sky1_base_pinctrl_probe);
583
584
585MODULE_AUTHOR("Jerry Zhu <Jerry.Zhu@cixtech.com>");
586MODULE_DESCRIPTION("Cix SKy1 pinctrl base driver");
587MODULE_LICENSE("GPL");
~/ Read-only file preview.