aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-rcar.c2
-rw-r--r--drivers/gpio/mvebu_gpio.c11
-rw-r--r--drivers/gpio/turris_omnia_mcu.c309
-rw-r--r--drivers/mtd/nand/raw/pxa3xx_nand.c2
-rw-r--r--drivers/pinctrl/mvebu/Kconfig7
-rw-r--r--drivers/pinctrl/mvebu/Makefile1
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-37xx.c189
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c589
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c4
-rw-r--r--drivers/pinctrl/pinctrl-generic.c100
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c3
13 files changed, 1165 insertions, 60 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index aaa152fae7..82a8bca270 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -598,4 +598,11 @@ config SLG7XL45106_I2C_GPO
8-bit gpo expander, all gpo lines are controlled by writing
value into data register.
+config TURRIS_OMNIA_MCU
+ bool "Turris Omnia MCU GPIO driver"
+ depends on DM_GPIO
+ default y if TARGET_TURRIS_OMNIA
+ help
+ Support for GPIOs on MCU connected to Turris Omnia via i2c.
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d7552762d0..219f37e0e4 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -75,3 +75,4 @@ obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o
obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o
obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o
+obj-$(CONFIG_$(SPL_TPL_)TURRIS_OMNIA_MCU) += turris_omnia_mcu.o
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 76f47027a3..138801850d 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -133,7 +133,7 @@ static int rcar_gpio_get_function(struct udevice *dev, unsigned offset)
static int rcar_gpio_request(struct udevice *dev, unsigned offset,
const char *label)
{
- return pinctrl_gpio_request(dev, offset);
+ return pinctrl_gpio_request(dev, offset, label);
}
static int rcar_gpio_free(struct udevice *dev, unsigned offset)
diff --git a/drivers/gpio/mvebu_gpio.c b/drivers/gpio/mvebu_gpio.c
index 4c1c68ee19..f706a6dfa4 100644
--- a/drivers/gpio/mvebu_gpio.c
+++ b/drivers/gpio/mvebu_gpio.c
@@ -5,6 +5,7 @@
#include <common.h>
#include <dm.h>
+#include <dm/pinctrl.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <errno.h>
@@ -22,7 +23,7 @@ struct mvebu_gpio_regs {
struct mvebu_gpio_priv {
struct mvebu_gpio_regs *regs;
- char name[2];
+ char name[sizeof("mvebuX_")];
};
static int mvebu_gpio_direction_input(struct udevice *dev, unsigned int gpio)
@@ -91,14 +92,18 @@ static int mvebu_gpio_probe(struct udevice *dev)
struct mvebu_gpio_priv *priv = dev_get_priv(dev);
priv->regs = dev_read_addr_ptr(dev);
- uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK;
- priv->name[0] = 'A' + dev_seq(dev);
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", MVEBU_GPIOS_PER_BANK);
+ sprintf(priv->name, "mvebu%d_", dev_seq(dev));
uc_priv->bank_name = priv->name;
return 0;
}
static const struct dm_gpio_ops mvebu_gpio_ops = {
+#if CONFIG_IS_ENABLED(PINCTRL_ARMADA_38X)
+ .request = pinctrl_gpio_request,
+ .rfree = pinctrl_gpio_free,
+#endif
.direction_input = mvebu_gpio_direction_input,
.direction_output = mvebu_gpio_direction_output,
.get_function = mvebu_gpio_get_function,
diff --git a/drivers/gpio/turris_omnia_mcu.c b/drivers/gpio/turris_omnia_mcu.c
new file mode 100644
index 0000000000..3e5d74e62c
--- /dev/null
+++ b/drivers/gpio/turris_omnia_mcu.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0+
+// (C) 2022 Pali Rohár <pali@kernel.org>
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+#include <linux/log2.h>
+
+enum commands_e {
+ CMD_GET_STATUS_WORD = 0x01,
+ CMD_GENERAL_CONTROL = 0x02,
+
+ /* available if STS_FEATURES_SUPPORTED bit set in status word */
+ CMD_GET_FEATURES = 0x10,
+
+ /* available if FEAT_EXT_CMDS bit is set in features */
+ CMD_GET_EXT_STATUS_DWORD = 0x11,
+ CMD_EXT_CONTROL = 0x12,
+ CMD_GET_EXT_CONTROL_STATUS = 0x13,
+};
+
+/* CMD_GET_STATUS_WORD */
+enum sts_word_e {
+ STS_MCU_TYPE_MASK = GENMASK(1, 0),
+ STS_MCU_TYPE_STM32 = 0,
+ STS_MCU_TYPE_GD32 = 1,
+ STS_MCU_TYPE_MKL = 2,
+ STS_FEATURES_SUPPORTED = BIT(2),
+ STS_USER_REGULATOR_NOT_SUPPORTED = BIT(3),
+ STS_CARD_DET = BIT(4),
+ STS_MSATA_IND = BIT(5),
+ STS_USB30_OVC = BIT(6),
+ STS_USB31_OVC = BIT(7),
+ STS_USB30_PWRON = BIT(8),
+ STS_USB31_PWRON = BIT(9),
+ STS_ENABLE_4V5 = BIT(10),
+ STS_BUTTON_MODE = BIT(11),
+ STS_BUTTON_PRESSED = BIT(12),
+ STS_BUTTON_COUNTER_MASK = GENMASK(15, 13)
+};
+
+/* CMD_GENERAL_CONTROL */
+enum ctl_byte_e {
+ CTL_LIGHT_RST = BIT(0),
+ CTL_HARD_RST = BIT(1),
+ /*CTL_RESERVED = BIT(2),*/
+ CTL_USB30_PWRON = BIT(3),
+ CTL_USB31_PWRON = BIT(4),
+ CTL_ENABLE_4V5 = BIT(5),
+ CTL_BUTTON_MODE = BIT(6),
+ CTL_BOOTLOADER = BIT(7)
+};
+
+/* CMD_GET_FEATURES */
+enum features_e {
+ FEAT_EXT_CMDS = BIT(1),
+};
+
+struct turris_omnia_mcu_info {
+ u16 features;
+};
+
+static int turris_omnia_mcu_get_function(struct udevice *dev, uint offset)
+{
+ struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+
+ switch (offset) {
+ /* bank 0 */
+ case 0 ... 15:
+ switch (offset) {
+ case ilog2(STS_USB30_PWRON):
+ case ilog2(STS_USB31_PWRON):
+ case ilog2(STS_ENABLE_4V5):
+ case ilog2(STS_BUTTON_MODE):
+ return GPIOF_OUTPUT;
+ default:
+ return GPIOF_INPUT;
+ }
+
+ /* bank 1 - supported only when FEAT_EXT_CMDS is set */
+ case (16 + 0) ... (16 + 31):
+ if (!(info->features & FEAT_EXT_CMDS))
+ return -EINVAL;
+ return GPIOF_INPUT;
+
+ /* bank 2 - supported only when FEAT_EXT_CMDS is set */
+ case (16 + 32 + 0) ... (16 + 32 + 15):
+ if (!(info->features & FEAT_EXT_CMDS))
+ return -EINVAL;
+ return GPIOF_OUTPUT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int turris_omnia_mcu_get_value(struct udevice *dev, uint offset)
+{
+ struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+ u8 val16[2];
+ u8 val32[4];
+ int ret;
+
+ switch (offset) {
+ /* bank 0 */
+ case 0 ... 15:
+ ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, val16, 2);
+ if (ret)
+ return ret;
+ return ((((u16)val16[1] << 8) | val16[0]) >> offset) & 0x1;
+
+ /* bank 1 - supported only when FEAT_EXT_CMDS is set */
+ case (16 + 0) ... (16 + 31):
+ if (!(info->features & FEAT_EXT_CMDS))
+ return -EINVAL;
+ ret = dm_i2c_read(dev, CMD_GET_EXT_STATUS_DWORD, val32, 4);
+ if (ret)
+ return ret;
+ return ((((u32)val32[3] << 24) | ((u32)val32[2] << 16) |
+ ((u32)val32[1] << 8) | val32[0]) >> (offset - 16)) & 0x1;
+
+ /* bank 2 - supported only when FEAT_EXT_CMDS is set */
+ case (16 + 32 + 0) ... (16 + 32 + 15):
+ if (!(info->features & FEAT_EXT_CMDS))
+ return -EINVAL;
+ ret = dm_i2c_read(dev, CMD_GET_EXT_CONTROL_STATUS, val16, 2);
+ if (ret)
+ return ret;
+ return ((((u16)val16[1] << 8) | val16[0]) >> (offset - 16 - 32)) & 0x1;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int turris_omnia_mcu_set_value(struct udevice *dev, uint offset, int value)
+{
+ struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+ u8 val[2];
+ int ret;
+ u8 reg;
+
+ switch (offset) {
+ /* bank 0 */
+ case ilog2(STS_USB30_PWRON):
+ reg = CMD_GENERAL_CONTROL;
+ val[1] = CTL_USB30_PWRON;
+ break;
+ case ilog2(STS_USB31_PWRON):
+ reg = CMD_GENERAL_CONTROL;
+ val[1] = CTL_USB31_PWRON;
+ break;
+ case ilog2(STS_ENABLE_4V5):
+ reg = CMD_GENERAL_CONTROL;
+ val[1] = CTL_ENABLE_4V5;
+ break;
+ case ilog2(STS_BUTTON_MODE):
+ reg = CMD_GENERAL_CONTROL;
+ val[1] = CTL_BUTTON_MODE;
+ break;
+
+ /* bank 2 - supported only when FEAT_EXT_CMDS is set */
+ case (16 + 32 + 0) ... (16 + 32 + 15):
+ if (!(info->features & FEAT_EXT_CMDS))
+ return -EINVAL;
+ reg = CMD_EXT_CONTROL;
+ val[1] = BIT(offset - 16 - 32);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ val[0] = value ? val[1] : 0;
+
+ ret = dm_i2c_write(dev, reg, val, 2);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int turris_omnia_mcu_direction_input(struct udevice *dev, uint offset)
+{
+ int ret;
+
+ ret = turris_omnia_mcu_get_function(dev, offset);
+ if (ret < 0)
+ return ret;
+ else if (ret != GPIOF_INPUT)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int turris_omnia_mcu_direction_output(struct udevice *dev, uint offset, int value)
+{
+ int ret;
+
+ ret = turris_omnia_mcu_get_function(dev, offset);
+ if (ret < 0)
+ return ret;
+ else if (ret != GPIOF_OUTPUT)
+ return -EOPNOTSUPP;
+
+ return turris_omnia_mcu_set_value(dev, offset, value);
+}
+
+static int turris_omnia_mcu_xlate(struct udevice *dev, struct gpio_desc *desc,
+ struct ofnode_phandle_args *args)
+{
+ uint bank, gpio, flags, offset;
+ int ret;
+
+ if (args->args_count != 3)
+ return -EINVAL;
+
+ bank = args->args[0];
+ gpio = args->args[1];
+ flags = args->args[2];
+
+ switch (bank) {
+ case 0:
+ if (gpio >= 16)
+ return -EINVAL;
+ offset = gpio;
+ break;
+ case 1:
+ if (gpio >= 32)
+ return -EINVAL;
+ offset = 16 + gpio;
+ break;
+ case 2:
+ if (gpio >= 16)
+ return -EINVAL;
+ offset = 16 + 32 + gpio;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = turris_omnia_mcu_get_function(dev, offset);
+ if (ret < 0)
+ return ret;
+
+ desc->offset = offset;
+ desc->flags = gpio_flags_xlate(flags);
+
+ return 0;
+}
+
+static const struct dm_gpio_ops turris_omnia_mcu_ops = {
+ .direction_input = turris_omnia_mcu_direction_input,
+ .direction_output = turris_omnia_mcu_direction_output,
+ .get_value = turris_omnia_mcu_get_value,
+ .set_value = turris_omnia_mcu_set_value,
+ .get_function = turris_omnia_mcu_get_function,
+ .xlate = turris_omnia_mcu_xlate,
+};
+
+static int turris_omnia_mcu_probe(struct udevice *dev)
+{
+ struct turris_omnia_mcu_info *info = dev_get_plat(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ u16 status;
+ u8 val[2];
+ int ret;
+
+ ret = dm_i2c_read(dev, CMD_GET_STATUS_WORD, val, 2);
+ if (ret) {
+ printf("Error: turris_omnia_mcu CMD_GET_STATUS_WORD failed: %d\n", ret);
+ return ret;
+ }
+
+ status = ((u16)val[1] << 8) | val[0];
+
+ if (status & STS_FEATURES_SUPPORTED) {
+ ret = dm_i2c_read(dev, CMD_GET_FEATURES, val, 2);
+ if (ret) {
+ printf("Error: turris_omnia_mcu CMD_GET_FEATURES failed: %d\n", ret);
+ return ret;
+ }
+ info->features = ((u16)val[1] << 8) | val[0];
+ }
+
+ uc_priv->bank_name = "mcu_";
+
+ if (info->features & FEAT_EXT_CMDS)
+ uc_priv->gpio_count = 16 + 32 + 16;
+ else
+ uc_priv->gpio_count = 16;
+
+ return 0;
+}
+
+static const struct udevice_id turris_omnia_mcu_ids[] = {
+ { .compatible = "cznic,turris-omnia-mcu" },
+ { }
+};
+
+U_BOOT_DRIVER(turris_omnia_mcu) = {
+ .name = "turris-omnia-mcu",
+ .id = UCLASS_GPIO,
+ .ops = &turris_omnia_mcu_ops,
+ .probe = turris_omnia_mcu_probe,
+ .plat_auto = sizeof(struct turris_omnia_mcu_info),
+ .of_match = turris_omnia_mcu_ids,
+};
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index 20d1aee7b3..9c29e8a6c2 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -429,7 +429,7 @@ static struct nand_ecclayout ecc_layout_8KB_bch8bit = {
static const struct udevice_id pxa3xx_nand_dt_ids[] = {
{
- .compatible = "marvell,mvebu-pxa3xx-nand",
+ .compatible = "marvell,armada370-nand-controller",
.data = PXA3XX_NAND_VARIANT_ARMADA370,
},
{
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index 07d4f3e216..574fb4dfb0 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -1,5 +1,12 @@
if ARCH_MVEBU
+config PINCTRL_ARMADA_38X
+ depends on ARMADA_38X && PINCTRL_FULL
+ bool "Armada 38x pin control driver"
+ help
+ Support pin multiplexing and pin configuration control on
+ Marvell's Armada-38x SoC.
+
config PINCTRL_ARMADA_37XX
depends on ARMADA_3700 && PINCTRL_FULL
bool "Armada 37xx pin control driver"
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index c2df96bf5b..15303d83a7 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -4,5 +4,6 @@
#
# https://spdx.org/licenses
+obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
obj-$(CONFIG_PINCTRL_ARMADA_37XX) += pinctrl-armada-37xx.o
obj-$(CONFIG_PINCTRL_ARMADA_8K) += pinctrl-mvebu.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index e76ef153e6..bb7a76baed 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -65,7 +65,6 @@ DECLARE_GLOBAL_DATA_PTR;
* belonging to the group
* @npins: Number of pins included in the second optional range
* @funcs: A list of pinmux functions that can be selected for this group.
- * @pins: List of the pins included in the group
*/
struct armada_37xx_pin_group {
const char *name;
@@ -76,7 +75,6 @@ struct armada_37xx_pin_group {
unsigned int extra_pin;
unsigned int extra_npins;
const char *funcs[NB_FUNCS];
- unsigned int *pins;
};
struct armada_37xx_pin_data {
@@ -97,8 +95,6 @@ struct armada_37xx_pinctrl {
const struct armada_37xx_pin_data *data;
struct udevice *dev;
struct pinctrl_dev *pctl_dev;
- struct armada_37xx_pin_group *groups;
- unsigned int ngroups;
struct armada_37xx_pmx_func *funcs;
unsigned int nfuncs;
};
@@ -113,6 +109,16 @@ struct armada_37xx_pinctrl {
.funcs = {_func1, _func2} \
}
+#define PIN_GRP_GPIO_0(_name, _start, _nr) \
+ { \
+ .name = _name, \
+ .start_pin = _start, \
+ .npins = _nr, \
+ .reg_mask = 0, \
+ .val = {0}, \
+ .funcs = {"gpio"} \
+ }
+
#define PIN_GRP_GPIO(_name, _start, _nr, _mask, _func1) \
{ \
.name = _name, \
@@ -170,6 +176,7 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
"pwm", "led"),
PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),
+ PIN_GRP_GPIO_0("gpio1_5", 5, 1),
PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"),
PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"),
PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"),
@@ -186,10 +193,13 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
PIN_GRP_GPIO("usb32_drvvbus0", 0, 1, BIT(0), "drvbus"),
PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"),
+ PIN_GRP_GPIO_0("gpio2_2", 2, 1),
PIN_GRP_GPIO("sdio_sb", 24, 6, BIT(2), "sdio"),
PIN_GRP_GPIO("rgmii", 6, 12, BIT(3), "mii"),
PIN_GRP_GPIO("smi", 18, 2, BIT(4), "smi"),
- PIN_GRP_GPIO("pcie1", 3, 3, BIT(5) | BIT(9) | BIT(10), "pcie"),
+ PIN_GRP_GPIO("pcie1", 3, 1, BIT(5), "pcie"), /* this actually controls "pcie1_reset" */
+ PIN_GRP_GPIO("pcie1_clkreq", 4, 1, BIT(9), "pcie"),
+ PIN_GRP_GPIO("pcie1_wakeup", 5, 1, BIT(10), "pcie"),
PIN_GRP_GPIO("ptp", 20, 3, BIT(11) | BIT(12) | BIT(13), "ptp"),
PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"),
PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"),
@@ -197,14 +207,14 @@ static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
"mii", "mii_err"),
};
-const struct armada_37xx_pin_data armada_37xx_pin_nb = {
+static const struct armada_37xx_pin_data armada_37xx_pin_nb = {
.nr_pins = 36,
.name = "GPIO1",
.groups = armada_37xx_nb_groups,
.ngroups = ARRAY_SIZE(armada_37xx_nb_groups),
};
-const struct armada_37xx_pin_data armada_37xx_pin_sb = {
+static const struct armada_37xx_pin_data armada_37xx_pin_sb = {
.nr_pins = 30,
.name = "GPIO2",
.groups = armada_37xx_sb_groups,
@@ -237,7 +247,7 @@ static int armada_37xx_pmx_get_groups_count(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
- return info->ngroups;
+ return info->data->ngroups;
}
static const char *armada_37xx_pmx_dummy_name = "_dummy";
@@ -247,10 +257,10 @@ static const char *armada_37xx_pmx_get_group_name(struct udevice *dev,
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
- if (!info->groups[selector].name)
+ if (!info->data->groups[selector].name)
return armada_37xx_pmx_dummy_name;
- return info->groups[selector].name;
+ return info->data->groups[selector].name;
}
static int armada_37xx_pmx_get_funcs_count(struct udevice *dev)
@@ -270,12 +280,13 @@ static const char *armada_37xx_pmx_get_func_name(struct udevice *dev,
static int armada_37xx_pmx_set_by_name(struct udevice *dev,
const char *name,
- struct armada_37xx_pin_group *grp)
+ struct armada_37xx_pin_group *grp,
+ bool warn_on_change)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
unsigned int reg = SELECTION;
unsigned int mask = grp->reg_mask;
- int func, val;
+ int func, val, old_func;
dev_dbg(info->dev, "enable function %s group %s\n",
name, grp->name);
@@ -287,6 +298,18 @@ static int armada_37xx_pmx_set_by_name(struct udevice *dev,
val = grp->val[func];
+ if (warn_on_change && val != (readl(info->base + reg) & mask)) {
+ for (old_func = 0; (old_func < NB_FUNCS) && grp->funcs[old_func]; old_func++) {
+ if (grp->val[old_func] == val)
+ break;
+ }
+ dev_warn(info->dev, "Warning: Changing MPPs %u-%u function from %s to %s...\n",
+ grp->start_pin, grp->start_pin + grp->npins - 1,
+ ((old_func < NB_FUNCS && grp->funcs[old_func]) ?
+ grp->funcs[old_func] : "unknown"),
+ name);
+ }
+
clrsetbits_le32(info->base + reg, mask, val);
return 0;
@@ -297,10 +320,112 @@ static int armada_37xx_pmx_group_set(struct udevice *dev,
unsigned func_selector)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
- struct armada_37xx_pin_group *grp = &info->groups[group_selector];
+ struct armada_37xx_pin_group *grp = &info->data->groups[group_selector];
const char *name = info->funcs[func_selector].name;
- return armada_37xx_pmx_set_by_name(dev, name, grp);
+ return armada_37xx_pmx_set_by_name(dev, name, grp, false);
+}
+
+static int armada_37xx_pmx_gpio_request_enable(struct udevice *dev, unsigned int selector)
+{
+ struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+ int ret = -ENOTSUPP;
+ int n;
+
+ /* Find all groups where is requested selector pin and set each group to gpio function */
+ for (n = 0; n < info->data->ngroups; n++) {
+ struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+ if ((selector >= grp->start_pin && selector < grp->start_pin + grp->npins) ||
+ (selector >= grp->extra_pin && selector < grp->extra_pin + grp->extra_npins)) {
+ ret = armada_37xx_pmx_set_by_name(dev, "gpio", grp, true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int armada_37xx_pmx_gpio_disable_free(struct udevice *dev, unsigned int selector)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static int armada_37xx_pmx_get_pins_count(struct udevice *dev)
+{
+ struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+
+ return info->data->nr_pins;
+}
+
+static const char *armada_37xx_pmx_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+ static char buf[sizeof("MPPx_XX")];
+
+ sprintf(buf, "MPP%c_%u", info->data->name[4], selector);
+ return buf;
+}
+
+static int armada_37xx_pmx_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ struct armada_37xx_pinctrl *info = dev_get_priv(dev);
+ int n;
+
+ /*
+ * First check if selected pin is in some extra pin group.
+ * Function in extra pin group is active only when it is not gpio.
+ */
+ for (n = 0; n < info->data->ngroups; n++) {
+ struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+ if (selector >= grp->extra_pin && selector < grp->extra_pin + grp->extra_npins) {
+ unsigned int reg = SELECTION;
+ unsigned int mask = grp->reg_mask;
+ int f, val;
+
+ val = (readl(info->base + reg) & mask);
+
+ for (f = 0; f < NB_FUNCS && grp->funcs[f]; f++) {
+ if (grp->val[f] == val) {
+ if (strcmp(grp->funcs[f], "gpio") != 0) {
+ strlcpy(buf, grp->funcs[f], size);
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* If pin is not active in some extra pin group then check regular groups. */
+ for (n = 0; n < info->data->ngroups; n++) {
+ struct armada_37xx_pin_group *grp = &info->data->groups[n];
+
+ if (selector >= grp->start_pin && selector < grp->start_pin + grp->npins) {
+ unsigned int reg = SELECTION;
+ unsigned int mask = grp->reg_mask;
+ int f, val;
+
+ val = (readl(info->base + reg) & mask);
+
+ for (f = 0; f < NB_FUNCS && grp->funcs[f]; f++) {
+ if (grp->val[f] == val) {
+ strlcpy(buf, grp->funcs[f], size);
+ return 0;
+ }
+ }
+
+ strlcpy(buf, "unknown", size);
+ return 0;
+ }
+ }
+
+ strlcpy(buf, "unknown", size);
+ return 0;
}
/**
@@ -352,21 +477,9 @@ static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info)
{
int n, num = 0, funcsize = info->data->nr_pins;
- for (n = 0; n < info->ngroups; n++) {
- struct armada_37xx_pin_group *grp = &info->groups[n];
- int i, j, f;
-
- grp->pins = devm_kzalloc(info->dev,
- (grp->npins + grp->extra_npins) *
- sizeof(*grp->pins), GFP_KERNEL);
- if (!grp->pins)
- return -ENOMEM;
-
- for (i = 0; i < grp->npins; i++)
- grp->pins[i] = grp->start_pin + i;
-
- for (j = 0; j < grp->extra_npins; j++)
- grp->pins[i+j] = grp->extra_pin + j;
+ for (n = 0; n < info->data->ngroups; n++) {
+ struct armada_37xx_pin_group *grp = &info->data->groups[n];
+ int f;
for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++) {
int ret;
@@ -416,8 +529,8 @@ static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
groups = funcs[n].groups;
- for (g = 0; g < info->ngroups; g++) {
- struct armada_37xx_pin_group *gp = &info->groups[g];
+ for (g = 0; g < info->data->ngroups; g++) {
+ struct armada_37xx_pin_group *gp = &info->data->groups[g];
int f;
for (f = 0; (f < NB_FUNCS) && gp->funcs[f]; f++) {
@@ -522,6 +635,8 @@ static int armada_37xx_gpio_probe(struct udevice *dev)
}
static const struct dm_gpio_ops armada_37xx_gpio_ops = {
+ .request = pinctrl_gpio_request,
+ .rfree = pinctrl_gpio_free,
.set_value = armada_37xx_gpio_set,
.get_value = armada_37xx_gpio_get,
.get_function = armada_37xx_gpio_get_direction,
@@ -574,16 +689,21 @@ static int armada_37xx_gpiochip_register(struct udevice *parent,
return 0;
}
-const struct pinctrl_ops armada_37xx_pinctrl_ops = {
+static const struct pinctrl_ops armada_37xx_pinctrl_ops = {
+ .get_pins_count = armada_37xx_pmx_get_pins_count,
+ .get_pin_name = armada_37xx_pmx_get_pin_name,
+ .get_pin_muxing = armada_37xx_pmx_get_pin_muxing,
.get_groups_count = armada_37xx_pmx_get_groups_count,
.get_group_name = armada_37xx_pmx_get_group_name,
.get_functions_count = armada_37xx_pmx_get_funcs_count,
.get_function_name = armada_37xx_pmx_get_func_name,
.pinmux_group_set = armada_37xx_pmx_group_set,
+ .gpio_request_enable = armada_37xx_pmx_gpio_request_enable,
+ .gpio_disable_free = armada_37xx_pmx_gpio_disable_free,
.set_state = pinctrl_generic_set_state,
};
-int armada_37xx_pinctrl_probe(struct udevice *dev)
+static int armada_37xx_pinctrl_probe(struct udevice *dev)
{
struct armada_37xx_pinctrl *info = dev_get_priv(dev);
const struct armada_37xx_pin_data *pin_data;
@@ -598,9 +718,6 @@ int armada_37xx_pinctrl_probe(struct udevice *dev)
return -ENODEV;
}
- info->groups = pin_data->groups;
- info->ngroups = pin_data->ngroups;
-
/*
* we allocate functions for number of pins and hope there are
* fewer unique functions than pins available
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
new file mode 100644
index 0000000000..252151f3e5
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// (C) 2022 Pali Rohár <pali@kernel.org>
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <asm/io.h>
+
+struct mvebu_mpp_ctrl_setting {
+ const char *name;
+ const char *subname;
+ u8 val;
+ u8 variant;
+};
+
+struct mvebu_mpp_mode {
+ const char *name;
+ size_t nsettings;
+ struct mvebu_mpp_ctrl_setting *settings;
+};
+
+#define MPP_MODE(_name, ...) \
+ { \
+ .name = _name, \
+ .nsettings = ARRAY_SIZE(( \
+ (struct mvebu_mpp_ctrl_setting[]) \
+ { __VA_ARGS__ })), \
+ .settings = (struct mvebu_mpp_ctrl_setting[]){ \
+ __VA_ARGS__ }, \
+ }
+
+#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \
+ { \
+ .val = _val, \
+ .name = _name, \
+ .subname = _subname, \
+ .variant = _mask, \
+ }
+
+#define MVEBU_MPPS_PER_REG 8
+#define MVEBU_MPP_BITS 4
+#define MVEBU_MPP_MASK 0xf
+
+enum {
+ V_88F6810 = BIT(0),
+ V_88F6820 = BIT(1),
+ V_88F6828 = BIT(2),
+ V_88F6810_PLUS = (V_88F6810 | V_88F6820 | V_88F6828),
+ V_88F6820_PLUS = (V_88F6820 | V_88F6828),
+};
+
+static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
+ MPP_MODE("mpp0",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "rxd", V_88F6810_PLUS)),
+ MPP_MODE("mpp1",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua0", "txd", V_88F6810_PLUS)),
+ MPP_MODE("mpp2",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sck", V_88F6810_PLUS)),
+ MPP_MODE("mpp3",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c0", "sda", V_88F6810_PLUS)),
+ MPP_MODE("mpp4",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_MODE("mpp5",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_MODE("mpp6",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge0", "crs", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs3", V_88F6810_PLUS)),
+ MPP_MODE("mpp7",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad9", V_88F6810_PLUS)),
+ MPP_MODE("mpp8",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad10", V_88F6810_PLUS)),
+ MPP_MODE("mpp9",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad11", V_88F6810_PLUS)),
+ MPP_MODE("mpp10",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad12", V_88F6810_PLUS)),
+ MPP_MODE("mpp11",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad13", V_88F6810_PLUS)),
+ MPP_MODE("mpp12",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie3", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE("mpp13",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie2", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE("mpp14",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "vttctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "we1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie3", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE("mpp15",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6810_PLUS)),
+ MPP_MODE("mpp16",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio slave", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie1", "clkreq", V_88F6820_PLUS)),
+ MPP_MODE("mpp17",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "sata0", "prsnt", V_88F6810_PLUS)),
+ MPP_MODE("mpp18",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "rxerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "trig", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6810_PLUS)),
+ MPP_MODE("mpp19",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "col", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "evreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ge0", "txerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
+ MPP_MODE("mpp20",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
+ MPP_MODE("mpp21",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "sata1", "prsnt", V_88F6810_PLUS)),
+ MPP_MODE("mpp22",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad0", V_88F6810_PLUS)),
+ MPP_MODE("mpp23",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad2", V_88F6810_PLUS)),
+ MPP_MODE("mpp24",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d4", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ready", V_88F6810_PLUS)),
+ MPP_MODE("mpp25",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d5", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs0", V_88F6810_PLUS)),
+ MPP_MODE("mpp26",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d6", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs1", V_88F6810_PLUS)),
+ MPP_MODE("mpp27",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "spi0", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txclkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d7", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "cs2", V_88F6810_PLUS)),
+ MPP_MODE("mpp28",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad5", V_88F6810_PLUS)),
+ MPP_MODE("mpp29",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale0", V_88F6810_PLUS)),
+ MPP_MODE("mpp30",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "oe", V_88F6810_PLUS)),
+ MPP_MODE("mpp31",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ale1", V_88F6810_PLUS)),
+ MPP_MODE("mpp32",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "txctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "we0", V_88F6810_PLUS)),
+ MPP_MODE("mpp33",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6810_PLUS)),
+ MPP_MODE("mpp34",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6810_PLUS)),
+ MPP_MODE("mpp35",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6810_PLUS)),
+ MPP_MODE("mpp36",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "trig", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6810_PLUS)),
+ MPP_MODE("mpp37",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6810_PLUS)),
+ MPP_MODE("mpp38",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ptp", "evreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad4", V_88F6810_PLUS)),
+ MPP_MODE("mpp39",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "a2", V_88F6810_PLUS)),
+ MPP_MODE("mpp40",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxd3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "sd0", "d2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad6", V_88F6810_PLUS)),
+ MPP_MODE("mpp41",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rxd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge1", "rxctl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "nand", "rb0", V_88F6810_PLUS)),
+ MPP_MODE("mpp42",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "txd", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "ad7", V_88F6810_PLUS)),
+ MPP_MODE("mpp43",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "nand", "rb1", V_88F6810_PLUS)),
+ MPP_MODE("mpp44",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6828)),
+ MPP_MODE("mpp45",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
+ MPP_MODE("mpp46",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
+ MPP_MODE("mpp47",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6828)),
+ MPP_MODE("mpp48",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "pclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie0", "clkreq", V_88F6810_PLUS)),
+ MPP_MODE("mpp49",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6828),
+ MPP_VAR_FUNCTION(3, "tdm", "fsync", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "pcie1", "clkreq", V_88F6820_PLUS)),
+ MPP_MODE("mpp50",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "drx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6810_PLUS)),
+ MPP_MODE("mpp51",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "dtx", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "trig", V_88F6810_PLUS)),
+ MPP_MODE("mpp52",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "int", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "clk", V_88F6810_PLUS)),
+ MPP_MODE("mpp53",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "tdm", "rst", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ptp", "evreq", V_88F6810_PLUS)),
+ MPP_MODE("mpp54",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "ge0", "txerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6810_PLUS)),
+ MPP_MODE("mpp55",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdio", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
+ MPP_MODE("mpp56",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "ge", "mdc", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
+ MPP_MODE("mpp57",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
+ MPP_MODE("mpp58",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie1", "clkreq", V_88F6820_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
+ MPP_MODE("mpp59",
+ MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6810_PLUS)),
+};
+
+static const char * const armada_38x_mpp_function_names[] = {
+ "gpio", /* make gpio always as function 0 */
+
+ "audio",
+ "dev",
+ "dram",
+ "ge",
+ "ge0",
+ "ge1",
+ "i2c0",
+ "i2c1",
+ "nand",
+ "pcie0",
+ "pcie1",
+ "pcie2",
+ "pcie3",
+ "ptp",
+ "ref",
+ "sata0",
+ "sata1",
+ "sata2",
+ "sata3",
+ "sd0",
+ "spi0",
+ "spi1",
+ "tdm",
+ "ua0",
+ "ua1",
+};
+
+struct armada_38x_pinctrl {
+ void __iomem *base;
+ u8 variant;
+};
+
+static int armada_38x_pinctrl_get_pins_count(struct udevice *dev)
+{
+ return ARRAY_SIZE(armada_38x_mpp_modes);
+}
+
+static const char *armada_38x_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector)
+{
+ return armada_38x_mpp_modes[selector].name;
+}
+
+static int armada_38x_pinctrl_get_functions_count(struct udevice *dev)
+{
+ return ARRAY_SIZE(armada_38x_mpp_function_names);
+}
+
+static const char *armada_38x_pinctrl_get_function_name(struct udevice *dev, unsigned int selector)
+{
+ return armada_38x_mpp_function_names[selector];
+}
+
+static int armada_38x_pinctrl_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ struct armada_38x_pinctrl *info = dev_get_priv(dev);
+ unsigned int off = (selector / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned int shift = (selector % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ const char *func_name = NULL;
+ const char *sub_name = NULL;
+ unsigned long config;
+ int i;
+
+ config = (readl(info->base + off) >> shift) & MVEBU_MPP_MASK;
+
+ for (i = 0; i < armada_38x_mpp_modes[selector].nsettings; i++) {
+ if (armada_38x_mpp_modes[selector].settings[i].val == config)
+ break;
+ }
+
+ if (i < armada_38x_mpp_modes[selector].nsettings) {
+ func_name = armada_38x_mpp_modes[selector].settings[i].name;
+ sub_name = armada_38x_mpp_modes[selector].settings[i].subname;
+ }
+
+ snprintf(buf, size, "%s%s%s",
+ func_name ? func_name : "unknown",
+ sub_name ? "_" : "",
+ sub_name ? sub_name : "");
+ return 0;
+}
+
+static int armada_38x_pinctrl_pinmux_set(struct udevice *dev, unsigned int pin_selector,
+ unsigned int func_selector)
+{
+ struct armada_38x_pinctrl *info = dev_get_priv(dev);
+ unsigned int off = (pin_selector / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ unsigned int shift = (pin_selector % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+ const char *func_name = armada_38x_mpp_function_names[func_selector];
+ unsigned long config, reg;
+ int i;
+
+ for (i = 0; i < armada_38x_mpp_modes[pin_selector].nsettings; i++) {
+ if (strcmp(armada_38x_mpp_modes[pin_selector].settings[i].name, func_name) == 0)
+ break;
+ }
+
+ if (i >= armada_38x_mpp_modes[pin_selector].nsettings)
+ return -EINVAL;
+
+ if (!(info->variant & armada_38x_mpp_modes[pin_selector].settings[i].variant))
+ return -EINVAL;
+
+ reg = readl(info->base + off) & ~(MVEBU_MPP_MASK << shift);
+ config = armada_38x_mpp_modes[pin_selector].settings[i].val;
+ writel(reg | (config << shift), info->base + off);
+
+ return 0;
+}
+
+static int armada_38x_pinctrl_gpio_request_enable(struct udevice *dev, unsigned int selector)
+{
+ char buf[20];
+
+ armada_38x_pinctrl_get_pin_muxing(dev, selector, buf, sizeof(buf));
+ if (strcmp(buf, "gpio") != 0)
+ printf("Warning: Changing mpp%u function from %s to gpio...\n", selector, buf);
+
+ return armada_38x_pinctrl_pinmux_set(dev, selector, 0); /* gpio is always function 0 */
+}
+
+static int armada_38x_pinctrl_gpio_disable_free(struct udevice *dev, unsigned int selector)
+{
+ /* nothing to do */
+ return 0;
+}
+
+static int armada_38x_pinctrl_set_state(struct udevice *dev, struct udevice *config)
+{
+ return pinctrl_generic_set_state_prefix(dev, config, "marvell,");
+}
+
+static int armada_38x_pinctrl_probe(struct udevice *dev)
+{
+ struct armada_38x_pinctrl *info = dev_get_priv(dev);
+
+ info->variant = (u8)dev_get_driver_data(dev);
+ info->base = dev_read_addr_ptr(dev);
+
+ if (!info->base)
+ return -EINVAL;
+
+ return 0;
+}
+
+struct pinctrl_ops armada_37xx_pinctrl_ops = {
+ .get_pins_count = armada_38x_pinctrl_get_pins_count,
+ .get_pin_name = armada_38x_pinctrl_get_pin_name,
+ .get_functions_count = armada_38x_pinctrl_get_functions_count,
+ .get_function_name = armada_38x_pinctrl_get_function_name,
+ .get_pin_muxing = armada_38x_pinctrl_get_pin_muxing,
+ .pinmux_set = armada_38x_pinctrl_pinmux_set,
+ .gpio_request_enable = armada_38x_pinctrl_gpio_request_enable,
+ .gpio_disable_free = armada_38x_pinctrl_gpio_disable_free,
+ .set_state = armada_38x_pinctrl_set_state,
+};
+
+static const struct udevice_id armada_38x_pinctrl_of_match[] = {
+ {
+ .compatible = "marvell,mv88f6810-pinctrl",
+ .data = V_88F6810,
+ },
+ {
+ .compatible = "marvell,mv88f6820-pinctrl",
+ .data = V_88F6820,
+ },
+ {
+ .compatible = "marvell,mv88f6828-pinctrl",
+ .data = V_88F6828,
+ },
+ { },
+};
+
+U_BOOT_DRIVER(armada_38x_pinctrl) = {
+ .name = "armada-38x-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(armada_38x_pinctrl_of_match),
+ .probe = armada_38x_pinctrl_probe,
+ .priv_auto = sizeof(struct armada_38x_pinctrl),
+ .ops = &armada_37xx_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 536c6aff96..fd49a97b5b 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -52,7 +52,9 @@ void mvebu_pinctl_emmc_set_mux(struct udevice *dev, u32 pin, u32 func)
EMMC_PHY_CTRL_SDPHY_EN);
}
} else if (!fdt_node_check_compatible(blob, node,
- "marvell,armada-8k-cpm-pinctrl")) {
+ "marvell,armada-8k-cpm-pinctrl") ||
+ !fdt_node_check_compatible(blob, node,
+ "marvell,armada-7k-pinctrl")) {
if ((pin == CP110_EMMC_CLK_PIN_ID) &&
(func == CP110_EMMC_CLK_FUNC)) {
clrbits_le32(priv->base_reg + CP_EMMC_PHY_CTRL_REG,
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
index 3c8e24088c..ec21d4ff83 100644
--- a/drivers/pinctrl/pinctrl-generic.c
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -234,6 +234,24 @@ enum pinmux_subnode_type {
PST_PINMUX,
};
+static const char *alloc_name_with_prefix(const char *name, const char *prefix)
+{
+ if (prefix) {
+ char *name_with_prefix = malloc(strlen(prefix) + sizeof("pins"));
+ if (name_with_prefix)
+ sprintf(name_with_prefix, "%s%s", prefix, name);
+ return name_with_prefix;
+ } else {
+ return name;
+ }
+}
+
+static void free_name_with_prefix(const char *name_with_prefix, const char *prefix)
+{
+ if (prefix)
+ free((char *)name_with_prefix);
+}
+
/**
* pinctrl_generic_set_state_one() - set state for a certain pin/group
* Apply all pin multiplexing and pin configurations specified by @config
@@ -248,9 +266,11 @@ enum pinmux_subnode_type {
*/
static int pinctrl_generic_set_state_one(struct udevice *dev,
struct udevice *config,
+ const char *prefix,
enum pinmux_subnode_type subnode_type,
unsigned selector)
{
+ const char *function_propname;
const char *propname;
const void *value;
struct ofprop property;
@@ -259,18 +279,26 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
assert(subnode_type != PST_NONE);
+ function_propname = alloc_name_with_prefix("function", prefix);
+ if (!function_propname)
+ return -ENOMEM;
+
dev_for_each_property(property, config) {
value = dev_read_prop_by_prop(&property, &propname, &len);
- if (!value)
+ if (!value) {
+ free_name_with_prefix(function_propname, prefix);
return -EINVAL;
+ }
/* pinmux subnodes already have their muxing set */
if (subnode_type != PST_PINMUX &&
- !strcmp(propname, "function")) {
+ !strcmp(propname, function_propname)) {
func_selector = pinmux_func_name_to_selector(dev,
value);
- if (func_selector < 0)
+ if (func_selector < 0) {
+ free_name_with_prefix(function_propname, prefix);
return func_selector;
+ }
ret = pinmux_enable_setting(dev,
subnode_type == PST_GROUP,
selector,
@@ -291,10 +319,13 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
selector, param, arg);
}
- if (ret)
+ if (ret) {
+ free_name_with_prefix(function_propname, prefix);
return ret;
+ }
}
+ free_name_with_prefix(function_propname, prefix);
return 0;
}
@@ -309,20 +340,34 @@ static int pinctrl_generic_set_state_one(struct udevice *dev,
*/
static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice *dev,
struct udevice *config,
+ const char *prefix,
int *count)
{
const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+ const char *propname;
- *count = dev_read_string_count(config, "pins");
+ propname = alloc_name_with_prefix("pins", prefix);
+ if (!propname)
+ return -ENOMEM;
+ *count = dev_read_string_count(config, propname);
+ free_name_with_prefix(propname, prefix);
if (*count >= 0)
return PST_PIN;
- *count = dev_read_string_count(config, "groups");
+ propname = alloc_name_with_prefix("groups", prefix);
+ if (!propname)
+ return -ENOMEM;
+ *count = dev_read_string_count(config, propname);
+ free_name_with_prefix(propname, prefix);
if (*count >= 0)
return PST_GROUP;
if (ops->pinmux_property_set) {
- *count = dev_read_size(config, "pinmux");
+ propname = alloc_name_with_prefix("pinmux", prefix);
+ if (!propname)
+ return -ENOMEM;
+ *count = dev_read_size(config, propname);
+ free_name_with_prefix(propname, prefix);
if (*count >= 0 && !(*count % sizeof(u32))) {
*count /= sizeof(u32);
return PST_PINMUX;
@@ -338,23 +383,30 @@ static enum pinmux_subnode_type pinctrl_generic_get_subnode_type(struct udevice
*
* @dev: pin controller device
* @config: pseudo device pointing to config node
+ * @prefix: device tree property prefix (e.g. vendor specific)
* @return: 0 on success, or negative error code on failure
*/
static int pinctrl_generic_set_state_subnode(struct udevice *dev,
- struct udevice *config)
+ struct udevice *config,
+ const char *prefix)
{
enum pinmux_subnode_type subnode_type;
+ const char *propname;
const char *name;
int count, selector, i, ret, scratch;
const u32 *pinmux_groups = NULL; /* prevent use-uninitialized warning */
- subnode_type = pinctrl_generic_get_subnode_type(dev, config, &count);
+ subnode_type = pinctrl_generic_get_subnode_type(dev, config, prefix, &count);
debug("%s(%s, %s): count=%d\n", __func__, dev->name, config->name,
count);
if (subnode_type == PST_PINMUX) {
- pinmux_groups = dev_read_prop(config, "pinmux", &scratch);
+ propname = alloc_name_with_prefix("pinmux", prefix);
+ if (!propname)
+ return -ENOMEM;
+ pinmux_groups = dev_read_prop(config, propname, &scratch);
+ free_name_with_prefix(propname, prefix);
if (!pinmux_groups)
return -EINVAL;
}
@@ -362,13 +414,21 @@ static int pinctrl_generic_set_state_subnode(struct udevice *dev,
for (i = 0; i < count; i++) {
switch (subnode_type) {
case PST_PIN:
- ret = dev_read_string_index(config, "pins", i, &name);
+ propname = alloc_name_with_prefix("pins", prefix);
+ if (!propname)
+ return -ENOMEM;
+ ret = dev_read_string_index(config, propname, i, &name);
+ free_name_with_prefix(propname, prefix);
if (ret)
return ret;
selector = pinctrl_pin_name_to_selector(dev, name);
break;
case PST_GROUP:
- ret = dev_read_string_index(config, "groups", i, &name);
+ propname = alloc_name_with_prefix("groups", prefix);
+ if (!propname)
+ return -ENOMEM;
+ ret = dev_read_string_index(config, propname, i, &name);
+ free_name_with_prefix(propname, prefix);
if (ret)
return ret;
selector = pinctrl_group_name_to_selector(dev, name);
@@ -390,8 +450,8 @@ static int pinctrl_generic_set_state_subnode(struct udevice *dev,
if (selector < 0)
return selector;
- ret = pinctrl_generic_set_state_one(dev, config, subnode_type,
- selector);
+ ret = pinctrl_generic_set_state_one(dev, config, prefix,
+ subnode_type, selector);
if (ret)
return ret;
}
@@ -399,22 +459,28 @@ static int pinctrl_generic_set_state_subnode(struct udevice *dev,
return 0;
}
-int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
+int pinctrl_generic_set_state_prefix(struct udevice *dev, struct udevice *config,
+ const char *prefix)
{
struct udevice *child;
int ret;
- ret = pinctrl_generic_set_state_subnode(dev, config);
+ ret = pinctrl_generic_set_state_subnode(dev, config, prefix);
if (ret)
return ret;
for (device_find_first_child(config, &child);
child;
device_find_next_child(&child)) {
- ret = pinctrl_generic_set_state_subnode(dev, child);
+ ret = pinctrl_generic_set_state_subnode(dev, child, prefix);
if (ret)
return ret;
}
return 0;
}
+
+int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
+{
+ return pinctrl_generic_set_state_prefix(dev, config, NULL);
+}
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 38ce2b5e0a..ce2d5ddf6d 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -222,9 +222,10 @@ pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset,
*
* @dev: GPIO peripheral device
* @offset: the GPIO pin offset from the GPIO controller
+ * @label: the GPIO pin label
* @return: 0 on success, or negative error code on failure
*/
-int pinctrl_gpio_request(struct udevice *dev, unsigned offset)
+int pinctrl_gpio_request(struct udevice *dev, unsigned offset, const char *label)
{
const struct pinctrl_ops *ops;
struct udevice *pctldev;