blob: c32d590a7e0ed5819b24bd3914297695e0ba9cae [file] [log] [blame]
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +02001// 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
Artur Kowalskid7587bf2025-03-30 21:11:54 +020040 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
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020045 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
59static 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");
Artur Kowalskid7587bf2025-03-30 21:11:54 +020066 if (function) {
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020067 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
Artur Kowalskid7587bf2025-03-30 21:11:54 +020072 func_id = i;
73 } else {
74 func_id = PMUX_FUNC_COUNT;
75 }
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020076
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
Artur Kowalskid7587bf2025-03-30 21:11:54 +020089 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
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +020095 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
103static 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 */
Svyatoslav Ryhel04673602024-12-06 17:50:58 +0200114 if (!strncmp(child->name, "conf", 4))
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200115 tegra_pinctrl_set_pin(child);
Svyatoslav Ryhel04673602024-12-06 17:50:58 +0200116 else if (!strncmp(child->name, "drive", 5))
Svyatoslav Ryhelc53f4c02023-11-26 17:54:03 +0200117 debug("%s: drive configuration is not supported\n", __func__);
118 else
119 tegra_pinctrl_set_func(child);
120 }
121
122 return 0;
123}
124
125static int tegra_pinctrl_get_pins_count(struct udevice *dev)
126{
127 return PMUX_PINGRP_COUNT;
128}
129
130static const char *tegra_pinctrl_get_pin_name(struct udevice *dev,
131 unsigned int selector)
132{
133 return tegra_pinctrl_to_pingrp[selector];
134}
135
136static int tegra_pinctrl_get_groups_count(struct udevice *dev)
137{
138 return PMUX_DRVGRP_COUNT;
139}
140
141static const char *tegra_pinctrl_get_group_name(struct udevice *dev,
142 unsigned int selector)
143{
144 return tegra_pinctrl_to_drvgrp[selector];
145}
146
147static int tegra_pinctrl_get_functions_count(struct udevice *dev)
148{
149 return PMUX_FUNC_COUNT;
150}
151
152static const char *tegra_pinctrl_get_function_name(struct udevice *dev,
153 unsigned int selector)
154{
155 return tegra_pinctrl_to_func[selector];
156}
157
158const 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
168static 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
180static const struct udevice_id tegra_pinctrl_ids[] = {
181 { .compatible = "nvidia,tegra20-pinmux" },
182 { },
183};
184
185U_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};