// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2023 * Svyatoslav Ryhel */ #include #include #include #include #include static void tegra_pinctrl_set_pin(struct udevice *config) { int i, count, pin_id, ret; int pull, tristate; const char **pins; ret = dev_read_u32(config, "nvidia,pull", &pull); if (ret) pull = ret; ret = dev_read_u32(config, "nvidia,tristate", &tristate); if (ret) tristate = ret; count = dev_read_string_list(config, "nvidia,pins", &pins); if (count < 0) { log_debug("%s: could not parse property nvidia,pins\n", __func__); return; } for (i = 0; i < count; i++) { for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++) if (tegra_pinctrl_to_pingrp[pin_id]) if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id])) break; if (pull >= 0) pinmux_set_pullupdown(pin_id, pull); if (tristate >= 0) { if (!tristate) pinmux_tristate_disable(pin_id); else pinmux_tristate_enable(pin_id); } } free(pins); } static void tegra_pinctrl_set_func(struct udevice *config) { int i, count, func_id, pin_id; const char *function; const char **pins; function = dev_read_string(config, "nvidia,function"); if (function) for (i = 0; i < PMUX_FUNC_COUNT; i++) if (tegra_pinctrl_to_func[i]) if (!strcmp(function, tegra_pinctrl_to_func[i])) break; func_id = i; count = dev_read_string_list(config, "nvidia,pins", &pins); if (count < 0) { log_debug("%s: could not parse property nvidia,pins\n", __func__); return; } for (i = 0; i < count; i++) { for (pin_id = 0; pin_id < PMUX_PINGRP_COUNT; pin_id++) if (tegra_pinctrl_to_pingrp[pin_id]) if (!strcmp(pins[i], tegra_pinctrl_to_pingrp[pin_id])) break; debug("%s(%d) muxed to %s(%d)\n", pins[i], pin_id, function, func_id); pinmux_set_func(pin_id, func_id); } free(pins); } static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config) { struct udevice *child; device_foreach_child(child, config) { /* * Tegra20 pinmux is set differently then any other * Tegra SOC. Nodes are arranged by function muxing, * then actual pins setup (with node name prefix * conf_*) and then drive setup. */ if (!strncmp(child->name, "conf_", 5)) tegra_pinctrl_set_pin(child); else if (!strncmp(child->name, "drive_", 6)) debug("%s: drive configuration is not supported\n", __func__); else tegra_pinctrl_set_func(child); } return 0; } static int tegra_pinctrl_get_pins_count(struct udevice *dev) { return PMUX_PINGRP_COUNT; } static const char *tegra_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector) { return tegra_pinctrl_to_pingrp[selector]; } static int tegra_pinctrl_get_groups_count(struct udevice *dev) { return PMUX_DRVGRP_COUNT; } static const char *tegra_pinctrl_get_group_name(struct udevice *dev, unsigned int selector) { return tegra_pinctrl_to_drvgrp[selector]; } static int tegra_pinctrl_get_functions_count(struct udevice *dev) { return PMUX_FUNC_COUNT; } static const char *tegra_pinctrl_get_function_name(struct udevice *dev, unsigned int selector) { return tegra_pinctrl_to_func[selector]; } const struct pinctrl_ops tegra_pinctrl_ops = { .get_pins_count = tegra_pinctrl_get_pins_count, .get_pin_name = tegra_pinctrl_get_pin_name, .get_groups_count = tegra_pinctrl_get_groups_count, .get_group_name = tegra_pinctrl_get_group_name, .get_functions_count = tegra_pinctrl_get_functions_count, .get_function_name = tegra_pinctrl_get_function_name, .set_state = tegra_pinctrl_set_state, }; static int tegra_pinctrl_bind(struct udevice *dev) { /* * Make sure that the pinctrl driver gets probed after binding * to provide initial configuration and assure that further * probed devices are working correctly. */ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); return 0; } static const struct udevice_id tegra_pinctrl_ids[] = { { .compatible = "nvidia,tegra20-pinmux" }, { }, }; U_BOOT_DRIVER(tegra_pinctrl) = { .name = "tegra_pinctrl", .id = UCLASS_PINCTRL, .of_match = tegra_pinctrl_ids, .bind = tegra_pinctrl_bind, .ops = &tegra_pinctrl_ops, };