blob: d5171b8be235ee99919ad8240dd2bcb0b9d43079 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2023
* Svyatoslav Ryhel <clamor95@gmail.com>
*/
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/pinctrl.h>
#include <stdlib.h>
#include <asm/arch/pinmux.h>
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,
};