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 
tegra_pinctrl_set_pin(struct udevice * config)14 static 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 (pin_id == PMUX_PINGRP_COUNT) {
41 			log_debug("%s: %s(%d) is not valid\n", __func__, pins[i], pin_id);
42 			continue;
43 		}
44 
45 		if (pull >= 0)
46 			pinmux_set_pullupdown(pin_id, pull);
47 
48 		if (tristate >= 0) {
49 			if (!tristate)
50 				pinmux_tristate_disable(pin_id);
51 			else
52 				pinmux_tristate_enable(pin_id);
53 		}
54 	}
55 
56 	free(pins);
57 }
58 
tegra_pinctrl_set_func(struct udevice * config)59 static void tegra_pinctrl_set_func(struct udevice *config)
60 {
61 	int i, count, func_id, pin_id;
62 	const char *function;
63 	const char **pins;
64 
65 	function = dev_read_string(config, "nvidia,function");
66 	if (function) {
67 		for (i = 0; i < PMUX_FUNC_COUNT; i++)
68 			if (tegra_pinctrl_to_func[i])
69 				if (!strcmp(function, tegra_pinctrl_to_func[i]))
70 					break;
71 
72 		func_id = i;
73 	} else {
74 		func_id = PMUX_FUNC_COUNT;
75 	}
76 
77 	count = dev_read_string_list(config, "nvidia,pins", &pins);
78 	if (count < 0) {
79 		log_debug("%s: could not parse property nvidia,pins\n", __func__);
80 		return;
81 	}
82 
83 	for (i = 0; i < count; i++) {
84 		for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++)
85 			if (tegra_pinctrl_to_pingrp[pin_id])
86 				if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id]))
87 					break;
88 
89 		if (func_id == PMUX_FUNC_COUNT || pin_id == PMUX_PINGRP_COUNT) {
90 			log_debug("%s: pin %s(%d) or function %s(%d) is not valid\n",
91 				  __func__, pins[i], pin_id, function, func_id);
92 			continue;
93 		}
94 
95 		debug("%s(%d) muxed to %s(%d)\n", pins[i], pin_id, function, func_id);
96 
97 		pinmux_set_func(pin_id, func_id);
98 	}
99 
100 	free(pins);
101 }
102 
tegra_pinctrl_set_state(struct udevice * dev,struct udevice * config)103 static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config)
104 {
105 	struct udevice *child;
106 
107 	device_foreach_child(child, config) {
108 		/*
109 		 * Tegra20 pinmux is set differently then any other
110 		 * Tegra SOC. Nodes are arranged by function muxing,
111 		 * then actual pins setup (with node name prefix
112 		 * conf_*) and then drive setup.
113 		 */
114 		if (!strncmp(child->name, "conf", 4))
115 			tegra_pinctrl_set_pin(child);
116 		else if (!strncmp(child->name, "drive", 5))
117 			debug("%s: drive configuration is not supported\n", __func__);
118 		else
119 			tegra_pinctrl_set_func(child);
120 	}
121 
122 	return 0;
123 }
124 
tegra_pinctrl_get_pins_count(struct udevice * dev)125 static int tegra_pinctrl_get_pins_count(struct udevice *dev)
126 {
127 	return PMUX_PINGRP_COUNT;
128 }
129 
tegra_pinctrl_get_pin_name(struct udevice * dev,unsigned int selector)130 static const char *tegra_pinctrl_get_pin_name(struct udevice *dev,
131 					      unsigned int selector)
132 {
133 	return tegra_pinctrl_to_pingrp[selector];
134 }
135 
tegra_pinctrl_get_groups_count(struct udevice * dev)136 static int tegra_pinctrl_get_groups_count(struct udevice *dev)
137 {
138 	return PMUX_DRVGRP_COUNT;
139 }
140 
tegra_pinctrl_get_group_name(struct udevice * dev,unsigned int selector)141 static const char *tegra_pinctrl_get_group_name(struct udevice *dev,
142 						unsigned int selector)
143 {
144 	return tegra_pinctrl_to_drvgrp[selector];
145 }
146 
tegra_pinctrl_get_functions_count(struct udevice * dev)147 static int tegra_pinctrl_get_functions_count(struct udevice *dev)
148 {
149 	return PMUX_FUNC_COUNT;
150 }
151 
tegra_pinctrl_get_function_name(struct udevice * dev,unsigned int selector)152 static const char *tegra_pinctrl_get_function_name(struct udevice *dev,
153 						   unsigned int selector)
154 {
155 	return tegra_pinctrl_to_func[selector];
156 }
157 
158 const struct pinctrl_ops tegra_pinctrl_ops = {
159 	.get_pins_count = tegra_pinctrl_get_pins_count,
160 	.get_pin_name = tegra_pinctrl_get_pin_name,
161 	.get_groups_count = tegra_pinctrl_get_groups_count,
162 	.get_group_name = tegra_pinctrl_get_group_name,
163 	.get_functions_count = tegra_pinctrl_get_functions_count,
164 	.get_function_name = tegra_pinctrl_get_function_name,
165 	.set_state = tegra_pinctrl_set_state,
166 };
167 
tegra_pinctrl_bind(struct udevice * dev)168 static int tegra_pinctrl_bind(struct udevice *dev)
169 {
170 	/*
171 	 * Make sure that the pinctrl driver gets probed after binding
172 	 * to provide initial configuration and assure that further
173 	 * probed devices are working correctly.
174 	 */
175 	dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
176 
177 	return 0;
178 }
179 
180 static const struct udevice_id tegra_pinctrl_ids[] = {
181 	{ .compatible = "nvidia,tegra20-pinmux" },
182 	{ },
183 };
184 
185 U_BOOT_DRIVER(tegra_pinctrl) = {
186 	.name		= "tegra_pinctrl",
187 	.id		= UCLASS_PINCTRL,
188 	.of_match	= tegra_pinctrl_ids,
189 	.bind		= tegra_pinctrl_bind,
190 	.ops		= &tegra_pinctrl_ops,
191 };
192