pinctrl: uniphier: support pin configuration
Support the following DT properties: "bias-disable" "bias-pull-up" "bias-pull-down" "bias-pull-pin-default" "input-enable" "input-disable" My main motivation is to support pull up/down biasing. For Pro5 and later SoCs, the pupdctrl register number is the same as the pinmux number, so this feature can be supported without having big pin tables. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
This commit is contained in:
parent
1b280978c0
commit
6a6b9d5dfd
@ -5,6 +5,7 @@
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sizes.h>
|
||||
@ -15,6 +16,7 @@
|
||||
|
||||
#define UNIPHIER_PINCTRL_PINMUX_BASE 0x1000
|
||||
#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x1700
|
||||
#define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0x1a00
|
||||
#define UNIPHIER_PINCTRL_IECTRL 0x1d00
|
||||
|
||||
static const char *uniphier_pinctrl_dummy_name = "_dummy";
|
||||
@ -55,8 +57,8 @@ static const char *uniphier_pinmux_get_function_name(struct udevice *dev,
|
||||
return priv->socdata->functions[selector];
|
||||
}
|
||||
|
||||
static void uniphier_pinconf_input_enable_perpin(struct udevice *dev,
|
||||
unsigned pin)
|
||||
static int uniphier_pinconf_input_enable_perpin(struct udevice *dev,
|
||||
unsigned int pin, int enable)
|
||||
{
|
||||
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
unsigned reg;
|
||||
@ -66,18 +68,30 @@ static void uniphier_pinconf_input_enable_perpin(struct udevice *dev,
|
||||
mask = BIT(pin % 32);
|
||||
|
||||
tmp = readl(priv->base + reg);
|
||||
tmp |= mask;
|
||||
if (enable)
|
||||
tmp |= mask;
|
||||
else
|
||||
tmp &= ~mask;
|
||||
writel(tmp, priv->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uniphier_pinconf_input_enable_legacy(struct udevice *dev,
|
||||
unsigned pin)
|
||||
static int uniphier_pinconf_input_enable_legacy(struct udevice *dev,
|
||||
unsigned int pin, int enable)
|
||||
{
|
||||
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
int pins_count = priv->socdata->pins_count;
|
||||
const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Multiple pins share one input enable, per-pin disabling is
|
||||
* impossible.
|
||||
*/
|
||||
if (!enable)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < pins_count; i++) {
|
||||
if (pins[i].number == pin) {
|
||||
unsigned int iectrl;
|
||||
@ -89,18 +103,115 @@ static void uniphier_pinconf_input_enable_legacy(struct udevice *dev,
|
||||
writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin)
|
||||
static int uniphier_pinconf_input_enable(struct udevice *dev,
|
||||
unsigned int pin, int enable)
|
||||
{
|
||||
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL)
|
||||
uniphier_pinconf_input_enable_perpin(dev, pin);
|
||||
return uniphier_pinconf_input_enable_perpin(dev, pin, enable);
|
||||
else
|
||||
uniphier_pinconf_input_enable_legacy(dev, pin);
|
||||
return uniphier_pinconf_input_enable_legacy(dev, pin, enable);
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(PINCONF)
|
||||
|
||||
static const struct pinconf_param uniphier_pinconf_params[] = {
|
||||
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
|
||||
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
|
||||
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
|
||||
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
|
||||
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
|
||||
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
|
||||
};
|
||||
|
||||
static int uniphier_pinconf_bias_set(struct udevice *dev, unsigned int pin,
|
||||
unsigned int param, unsigned int arg)
|
||||
{
|
||||
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
unsigned int enable = 1;
|
||||
unsigned int reg;
|
||||
u32 mask, tmp;
|
||||
|
||||
if (!(priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE))
|
||||
return -ENOTSUPP;
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
enable = 0;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
if (arg == 0) /* total bias is not supported */
|
||||
return -EINVAL;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
|
||||
if (arg == 0) /* configuration ignored */
|
||||
return 0;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pin / 32 * 4;
|
||||
mask = BIT(pin % 32);
|
||||
|
||||
tmp = readl(priv->base + reg);
|
||||
if (enable)
|
||||
tmp |= mask;
|
||||
else
|
||||
tmp &= ~mask;
|
||||
writel(tmp, priv->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_pinconf_set_one(struct udevice *dev, unsigned int pin,
|
||||
unsigned int param, unsigned int arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
|
||||
ret = uniphier_pinconf_bias_set(dev, pin, param, arg);
|
||||
break;
|
||||
case PIN_CONFIG_INPUT_ENABLE:
|
||||
ret = uniphier_pinconf_input_enable(dev, pin, arg);
|
||||
break;
|
||||
default:
|
||||
printf("unsupported configuration parameter %u\n", param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uniphier_pinconf_group_set(struct udevice *dev,
|
||||
unsigned int group_selector,
|
||||
unsigned int param, unsigned int arg)
|
||||
{
|
||||
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
const struct uniphier_pinctrl_group *grp =
|
||||
&priv->socdata->groups[group_selector];
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < grp->num_pins; i++) {
|
||||
ret = uniphier_pinconf_set_one(dev, grp->pins[i], param, arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IS_ENABLED(PINCONF) */
|
||||
|
||||
static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
|
||||
int muxval)
|
||||
{
|
||||
@ -112,7 +223,7 @@ static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
|
||||
u32 tmp;
|
||||
|
||||
/* some pins need input-enabling */
|
||||
uniphier_pinconf_input_enable(dev, pin);
|
||||
uniphier_pinconf_input_enable(dev, pin, 1);
|
||||
|
||||
if (muxval < 0)
|
||||
return; /* dedicated pin; nothing to do for pin-mux */
|
||||
@ -174,6 +285,11 @@ const struct pinctrl_ops uniphier_pinctrl_ops = {
|
||||
.get_functions_count = uniphier_pinmux_get_functions_count,
|
||||
.get_function_name = uniphier_pinmux_get_function_name,
|
||||
.pinmux_group_set = uniphier_pinmux_group_set,
|
||||
#if CONFIG_IS_ENABLED(PINCONF)
|
||||
.pinconf_num_params = ARRAY_SIZE(uniphier_pinconf_params),
|
||||
.pinconf_params = uniphier_pinconf_params,
|
||||
.pinconf_group_set = uniphier_pinconf_group_set,
|
||||
#endif
|
||||
.set_state = pinctrl_generic_set_state,
|
||||
};
|
||||
|
||||
|
@ -92,7 +92,8 @@ static struct uniphier_pinctrl_socdata uniphier_ld11_pinctrl_socdata = {
|
||||
.groups_count = ARRAY_SIZE(uniphier_ld11_groups),
|
||||
.functions = uniphier_ld11_functions,
|
||||
.functions_count = ARRAY_SIZE(uniphier_ld11_functions),
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE |
|
||||
UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
|
||||
};
|
||||
|
||||
static int uniphier_ld11_pinctrl_probe(struct udevice *dev)
|
||||
|
@ -106,7 +106,8 @@ static struct uniphier_pinctrl_socdata uniphier_ld20_pinctrl_socdata = {
|
||||
.groups_count = ARRAY_SIZE(uniphier_ld20_groups),
|
||||
.functions = uniphier_ld20_functions,
|
||||
.functions_count = ARRAY_SIZE(uniphier_ld20_functions),
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE |
|
||||
UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL,
|
||||
};
|
||||
|
||||
static int uniphier_ld20_pinctrl_probe(struct udevice *dev)
|
||||
|
@ -140,6 +140,7 @@ static struct uniphier_pinctrl_socdata uniphier_ld6b_pinctrl_socdata = {
|
||||
.groups_count = ARRAY_SIZE(uniphier_ld6b_groups),
|
||||
.functions = uniphier_ld6b_functions,
|
||||
.functions_count = ARRAY_SIZE(uniphier_ld6b_functions),
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE,
|
||||
};
|
||||
|
||||
static int uniphier_ld6b_pinctrl_probe(struct udevice *dev)
|
||||
|
@ -147,7 +147,8 @@ static struct uniphier_pinctrl_socdata uniphier_pro5_pinctrl_socdata = {
|
||||
.groups_count = ARRAY_SIZE(uniphier_pro5_groups),
|
||||
.functions = uniphier_pro5_functions,
|
||||
.functions_count = ARRAY_SIZE(uniphier_pro5_functions),
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE |
|
||||
UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE,
|
||||
};
|
||||
|
||||
static int uniphier_pro5_pinctrl_probe(struct udevice *dev)
|
||||
|
@ -140,6 +140,7 @@ static struct uniphier_pinctrl_socdata uniphier_pxs2_pinctrl_socdata = {
|
||||
.groups_count = ARRAY_SIZE(uniphier_pxs2_groups),
|
||||
.functions = uniphier_pxs2_functions,
|
||||
.functions_count = ARRAY_SIZE(uniphier_pxs2_functions),
|
||||
.caps = UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE,
|
||||
};
|
||||
|
||||
static int uniphier_pxs2_pinctrl_probe(struct udevice *dev)
|
||||
|
@ -67,6 +67,7 @@ struct uniphier_pinctrl_socdata {
|
||||
const char * const *functions;
|
||||
int functions_count;
|
||||
unsigned caps;
|
||||
#define UNIPHIER_PINCTRL_CAPS_PUPD_SIMPLE BIT(3)
|
||||
#define UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL BIT(2)
|
||||
#define UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE BIT(1)
|
||||
#define UNIPHIER_PINCTRL_CAPS_MUX_4BIT BIT(0)
|
||||
|
Loading…
Reference in New Issue
Block a user