diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index ee820a57a0e0b6aa2f570dab65c60eba2c492aab..162642d7289bc3cbeb25bb7af9b17347b97d8f56 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -2,6 +2,7 @@ if ARCH_MESON config PINCTRL_MESON select PINCTRL_GENERIC + select PINCONF bool config PINCTRL_MESON_GX_PMX diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c index c82413d08f34d3041e5d0a937436be84866caf5a..f23b188f2f3f372250eebd629fccda886e0dcd7c 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c @@ -93,6 +93,12 @@ static int meson_axg_pinmux_group_set(struct udevice *dev, return 0; } +const struct pinconf_param meson_axg_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 }, +}; + const struct pinctrl_ops meson_axg_pinctrl_ops = { .get_groups_count = meson_pinctrl_get_groups_count, .get_group_name = meson_pinctrl_get_group_name, @@ -100,6 +106,10 @@ const struct pinctrl_ops meson_axg_pinctrl_ops = { .get_function_name = meson_pinmux_get_function_name, .pinmux_group_set = meson_axg_pinmux_group_set, .set_state = pinctrl_generic_set_state, + .pinconf_params = meson_axg_pinconf_params, + .pinconf_num_params = ARRAY_SIZE(meson_axg_pinconf_params), + .pinconf_set = meson_pinconf_set, + .pinconf_group_set = meson_pinconf_group_set, }; static int meson_axg_gpio_request(struct udevice *dev, diff --git a/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c index fc1538ea719eaed04062f25beb56b1abdd16b705..cf72576b6ce2f7c8dee7abda566806222a33d9e2 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c @@ -72,6 +72,12 @@ static int meson_gx_pinmux_group_set(struct udevice *dev, return 0; } +const struct pinconf_param meson_gx_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 }, +}; + const struct pinctrl_ops meson_gx_pinctrl_ops = { .get_groups_count = meson_pinctrl_get_groups_count, .get_group_name = meson_pinctrl_get_group_name, @@ -79,6 +85,10 @@ const struct pinctrl_ops meson_gx_pinctrl_ops = { .get_function_name = meson_pinmux_get_function_name, .pinmux_group_set = meson_gx_pinmux_group_set, .set_state = pinctrl_generic_set_state, + .pinconf_params = meson_gx_pinconf_params, + .pinconf_num_params = ARRAY_SIZE(meson_gx_pinconf_params), + .pinconf_set = meson_pinconf_set, + .pinconf_group_set = meson_pinconf_group_set, }; static const struct dm_gpio_ops meson_gx_gpio_ops = { diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index b539749752c8420659870b6bd23c093fb9a85777..fa3d78858a9e0f615021509f26ca0e75a31a1693 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -57,7 +57,7 @@ static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset, enum meson_reg_type reg_type, unsigned int *reg, unsigned int *bit) { - struct meson_pinctrl *priv = dev_get_priv(dev->parent); + struct meson_pinctrl *priv = dev_get_priv(dev); struct meson_bank *bank = NULL; struct meson_reg_desc *desc; unsigned int pin; @@ -89,7 +89,8 @@ int meson_gpio_get(struct udevice *dev, unsigned int offset) unsigned int reg, bit; int ret; - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_IN, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, ®, + &bit); if (ret) return ret; @@ -102,7 +103,8 @@ int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) unsigned int reg, bit; int ret; - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, ®, + &bit); if (ret) return ret; @@ -117,7 +119,8 @@ int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) unsigned int reg, bit, val; int ret; - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®, + &bit); if (ret) return ret; @@ -132,7 +135,8 @@ int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) unsigned int reg, bit; int ret; - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®, + &bit); if (ret) return ret; @@ -148,13 +152,15 @@ int meson_gpio_direction_output(struct udevice *dev, unsigned int reg, bit; int ret; - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®, + &bit); if (ret) return ret; clrbits_le32(priv->reg_gpio + reg, BIT(bit)); - ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, ®, + &bit); if (ret) return ret; @@ -163,6 +169,72 @@ int meson_gpio_direction_output(struct udevice *dev, return 0; } +static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin, + unsigned int param) +{ + struct meson_pinctrl *priv = dev_get_priv(dev); + unsigned int offset = pin - priv->data->pin_base; + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, ®, &bit); + if (ret) + return ret; + + if (param == PIN_CONFIG_BIAS_DISABLE) { + clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0); + return 0; + } + + /* othewise, enable the bias and select level */ + clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 1); + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_pull + reg, BIT(bit), + param == PIN_CONFIG_BIAS_PULL_UP); + + return 0; +} + +int meson_pinconf_set(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: + ret = meson_pinconf_bias_set(dev, pin, param); + break; + + default: + dev_err(dev, "unsupported configuration parameter %u\n", param); + return -EINVAL; + } + + return ret; +} + +int meson_pinconf_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int param, unsigned int arg) +{ + struct meson_pinctrl *priv = dev_get_priv(dev); + struct meson_pmx_group *grp = &priv->data->groups[group_selector]; + int i, ret; + + for (i = 0; i < grp->num_pins; i++) { + ret = meson_pinconf_set(dev, grp->pins[i], param, arg); + if (ret) + return ret; + } + + return 0; +} + int meson_gpio_probe(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); @@ -240,6 +312,21 @@ int meson_pinctrl_probe(struct udevice *dev) return -EINVAL; } priv->reg_gpio = (void __iomem *)addr; + + addr = parse_address(gpio, "pull", na, ns); + if (addr == FDT_ADDR_T_NONE) { + debug("pull address not found\n"); + return -EINVAL; + } + priv->reg_pull = (void __iomem *)addr; + + addr = parse_address(gpio, "pull-enable", na, ns); + /* Use pull region if pull-enable one is not present */ + if (addr == FDT_ADDR_T_NONE) + priv->reg_pullen = priv->reg_pull; + else + priv->reg_pullen = (void __iomem *)addr; + priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev); /* Lookup GPIO driver */ diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index bdee721fc0070b56249045c65b2332c3465c0fb6..28085a7495d461b3edf947c92e0db07199d5241a 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -39,6 +39,8 @@ struct meson_pinctrl { struct meson_pinctrl_data *data; void __iomem *reg_mux; void __iomem *reg_gpio; + void __iomem *reg_pull; + void __iomem *reg_pullen; }; /** @@ -130,4 +132,10 @@ int meson_gpio_direction_output(struct udevice *dev, unsigned int offset, int value); int meson_gpio_probe(struct udevice *dev); +int meson_pinconf_set(struct udevice *dev, unsigned int pin, + unsigned int param, unsigned int arg); +int meson_pinconf_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int param, unsigned int arg); + #endif /* __PINCTRL_MESON_H__ */