1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *  (C) Copyright 2023
4 *  Svyatoslav Ryhel <clamor95@gmail.com>
5 */
6
7#include <dm.h>
8#include <dm/device_compat.h>
9#include <dm/pinctrl.h>
10#include <stdlib.h>
11
12#include <asm/arch/pinmux.h>
13
14static void tegra_pinctrl_set_pin(struct udevice *config)
15{
16	int i, count, pin_id, ret;
17	int pull, tristate;
18	const char **pins;
19
20	ret = dev_read_u32(config, "nvidia,pull", &pull);
21	if (ret)
22		pull = ret;
23
24	ret = dev_read_u32(config, "nvidia,tristate", &tristate);
25	if (ret)
26		tristate = ret;
27
28	count = dev_read_string_list(config, "nvidia,pins", &pins);
29	if (count < 0) {
30		log_debug("%s: could not parse property nvidia,pins\n", __func__);
31		return;
32	}
33
34	for (i = 0; i < count; i++) {
35		for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++)
36			if (tegra_pinctrl_to_pingrp[pin_id])
37				if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id]))
38					break;
39
40		if (pull >= 0)
41			pinmux_set_pullupdown(pin_id, pull);
42
43		if (tristate >= 0) {
44			if (!tristate)
45				pinmux_tristate_disable(pin_id);
46			else
47				pinmux_tristate_enable(pin_id);
48		}
49	}
50
51	free(pins);
52}
53
54static void tegra_pinctrl_set_func(struct udevice *config)
55{
56	int i, count, func_id, pin_id;
57	const char *function;
58	const char **pins;
59
60	function = dev_read_string(config, "nvidia,function");
61	if (function)
62		for (i = 0; i < PMUX_FUNC_COUNT; i++)
63			if (tegra_pinctrl_to_func[i])
64				if (!strcmp(function, tegra_pinctrl_to_func[i]))
65					break;
66
67	func_id = i;
68
69	count = dev_read_string_list(config, "nvidia,pins", &pins);
70	if (count < 0) {
71		log_debug("%s: could not parse property nvidia,pins\n", __func__);
72		return;
73	}
74
75	for (i = 0; i < count; i++) {
76		for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++)
77			if (tegra_pinctrl_to_pingrp[pin_id])
78				if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id]))
79					break;
80
81		debug("%s(%d) muxed to %s(%d)\n", pins[i], pin_id, function, func_id);
82
83		pinmux_set_func(pin_id, func_id);
84	}
85
86	free(pins);
87}
88
89static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config)
90{
91	struct udevice *child;
92
93	device_foreach_child(child, config) {
94		/*
95		 * Tegra20 pinmux is set differently then any other
96		 * Tegra SOC. Nodes are arranged by function muxing,
97		 * then actual pins setup (with node name prefix
98		 * conf_*) and then drive setup.
99		 */
100		if (!strncmp(child->name, "conf_", 5))
101			tegra_pinctrl_set_pin(child);
102		else if (!strncmp(child->name, "drive_", 6))
103			debug("%s: drive configuration is not supported\n", __func__);
104		else
105			tegra_pinctrl_set_func(child);
106	}
107
108	return 0;
109}
110
111static int tegra_pinctrl_get_pins_count(struct udevice *dev)
112{
113	return PMUX_PINGRP_COUNT;
114}
115
116static const char *tegra_pinctrl_get_pin_name(struct udevice *dev,
117					      unsigned int selector)
118{
119	return tegra_pinctrl_to_pingrp[selector];
120}
121
122static int tegra_pinctrl_get_groups_count(struct udevice *dev)
123{
124	return PMUX_DRVGRP_COUNT;
125}
126
127static const char *tegra_pinctrl_get_group_name(struct udevice *dev,
128						unsigned int selector)
129{
130	return tegra_pinctrl_to_drvgrp[selector];
131}
132
133static int tegra_pinctrl_get_functions_count(struct udevice *dev)
134{
135	return PMUX_FUNC_COUNT;
136}
137
138static const char *tegra_pinctrl_get_function_name(struct udevice *dev,
139						   unsigned int selector)
140{
141	return tegra_pinctrl_to_func[selector];
142}
143
144const struct pinctrl_ops tegra_pinctrl_ops = {
145	.get_pins_count = tegra_pinctrl_get_pins_count,
146	.get_pin_name = tegra_pinctrl_get_pin_name,
147	.get_groups_count = tegra_pinctrl_get_groups_count,
148	.get_group_name = tegra_pinctrl_get_group_name,
149	.get_functions_count = tegra_pinctrl_get_functions_count,
150	.get_function_name = tegra_pinctrl_get_function_name,
151	.set_state = tegra_pinctrl_set_state,
152};
153
154static int tegra_pinctrl_bind(struct udevice *dev)
155{
156	/*
157	 * Make sure that the pinctrl driver gets probed after binding
158	 * to provide initial configuration and assure that further
159	 * probed devices are working correctly.
160	 */
161	dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
162
163	return 0;
164}
165
166static const struct udevice_id tegra_pinctrl_ids[] = {
167	{ .compatible = "nvidia,tegra20-pinmux" },
168	{ },
169};
170
171U_BOOT_DRIVER(tegra_pinctrl) = {
172	.name		= "tegra_pinctrl",
173	.id		= UCLASS_PINCTRL,
174	.of_match	= tegra_pinctrl_ids,
175	.bind		= tegra_pinctrl_bind,
176	.ops		= &tegra_pinctrl_ops,
177};
178