diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /drivers/pinctrl/mvebu | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'drivers/pinctrl/mvebu')
| -rw-r--r-- | drivers/pinctrl/mvebu/Kconfig | 57 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/Makefile | 14 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-ac5.c | 260 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-370.c | 403 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-375.c | 421 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 1184 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-38x.c | 428 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-39x.c | 410 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-ap806.c | 133 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-cp110.c | 691 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-armada-xp.c | 643 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-dove.c | 873 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-kirkwood.c | 485 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-mvebu.c | 844 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-mvebu.h | 211 | ||||
| -rw-r--r-- | drivers/pinctrl/mvebu/pinctrl-orion.c | 241 |
16 files changed, 7298 insertions, 0 deletions
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig new file mode 100644 index 000000000..aa5883f09 --- /dev/null +++ b/drivers/pinctrl/mvebu/Kconfig @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only +config PINCTRL_MVEBU + bool + select PINMUX + select PINCONF + +config PINCTRL_DOVE + bool + select PINCTRL_MVEBU + select MFD_SYSCON + +config PINCTRL_KIRKWOOD + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_370 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_375 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_38X + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_39X + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_AP806 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_CP110 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_XP + bool + select PINCTRL_MVEBU + +config PINCTRL_ORION + bool + select PINCTRL_MVEBU + +config PINCTRL_AC5 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_37XX + bool + select GENERIC_PINCONF + select MFD_SYSCON + select PINCONF + select PINMUX diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile new file mode 100644 index 000000000..23458ab17 --- /dev/null +++ b/drivers/pinctrl/mvebu/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o +obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o +obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o +obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o +obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o +obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o +obj-$(CONFIG_PINCTRL_ARMADA_39X) += pinctrl-armada-39x.o +obj-$(CONFIG_PINCTRL_ARMADA_AP806) += pinctrl-armada-ap806.o +obj-$(CONFIG_PINCTRL_ARMADA_CP110) += pinctrl-armada-cp110.o +obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o +obj-$(CONFIG_PINCTRL_ARMADA_37XX) += pinctrl-armada-37xx.o +obj-$(CONFIG_PINCTRL_ORION) += pinctrl-orion.o +obj-$(CONFIG_PINCTRL_AC5) += pinctrl-ac5.o diff --git a/drivers/pinctrl/mvebu/pinctrl-ac5.c b/drivers/pinctrl/mvebu/pinctrl-ac5.c new file mode 100644 index 000000000..09ddfc434 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-ac5.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell ac5 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2021 Marvell + * + * Noam Liron <lnoam@marvell.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-mvebu.h" + +static struct mvebu_mpp_mode ac5_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d0"), + MPP_FUNCTION(2, "nand", "io4")), + MPP_MODE(1, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d1"), + MPP_FUNCTION(2, "nand", "io3")), + MPP_MODE(2, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d2"), + MPP_FUNCTION(2, "nand", "io2")), + MPP_MODE(3, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d3"), + MPP_FUNCTION(2, "nand", "io7")), + MPP_MODE(4, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d4"), + MPP_FUNCTION(2, "nand", "io6"), + MPP_FUNCTION(3, "uart3", "txd"), + MPP_FUNCTION(4, "uart2", "txd")), + MPP_MODE(5, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d5"), + MPP_FUNCTION(2, "nand", "io5"), + MPP_FUNCTION(3, "uart3", "rxd"), + MPP_FUNCTION(4, "uart2", "rxd")), + MPP_MODE(6, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d6"), + MPP_FUNCTION(2, "nand", "io0"), + MPP_FUNCTION(3, "i2c1", "sck")), + MPP_MODE(7, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d7"), + MPP_FUNCTION(2, "nand", "io1"), + MPP_FUNCTION(3, "i2c1", "sda")), + MPP_MODE(8, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "clk"), + MPP_FUNCTION(2, "nand", "wen")), + MPP_MODE(9, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "cmd"), + MPP_FUNCTION(2, "nand", "ale")), + MPP_MODE(10, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "ds"), + MPP_FUNCTION(2, "nand", "cle")), + MPP_MODE(11, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "rst"), + MPP_FUNCTION(2, "nand", "cen")), + MPP_MODE(12, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "clk")), + MPP_MODE(13, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "csn")), + MPP_MODE(14, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "mosi")), + MPP_MODE(15, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "miso")), + MPP_MODE(16, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "wpn"), + MPP_FUNCTION(2, "nand", "ren"), + MPP_FUNCTION(3, "uart1", "txd")), + MPP_MODE(17, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "spi0", "hold"), + MPP_FUNCTION(2, "nand", "rb"), + MPP_FUNCTION(3, "uart1", "rxd")), + MPP_MODE(18, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "tsen_int", NULL), + MPP_FUNCTION(2, "uart2", "rxd"), + MPP_FUNCTION(3, "wd_int", NULL)), + MPP_MODE(19, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev_init_done", NULL), + MPP_FUNCTION(2, "uart2", "txd")), + MPP_MODE(20, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(2, "i2c1", "sck"), + MPP_FUNCTION(3, "spi1", "clk"), + MPP_FUNCTION(4, "uart3", "txd")), + MPP_MODE(21, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(2, "i2c1", "sda"), + MPP_FUNCTION(3, "spi1", "csn"), + MPP_FUNCTION(4, "uart3", "rxd")), + MPP_MODE(22, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(3, "spi1", "mosi")), + MPP_MODE(23, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(3, "spi1", "miso")), + MPP_MODE(24, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "wd_int", NULL), + MPP_FUNCTION(2, "uart2", "txd"), + MPP_FUNCTION(3, "uartsd", "txd")), + MPP_MODE(25, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "int_out", NULL), + MPP_FUNCTION(2, "uart2", "rxd"), + MPP_FUNCTION(3, "uartsd", "rxd")), + MPP_MODE(26, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "i2c0", "sck"), + MPP_FUNCTION(2, "ptp", "clk1"), + MPP_FUNCTION(3, "uart3", "txd")), + MPP_MODE(27, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "i2c0", "sda"), + MPP_FUNCTION(2, "ptp", "pulse"), + MPP_FUNCTION(3, "uart3", "rxd")), + MPP_MODE(28, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "xg", "mdio"), + MPP_FUNCTION(2, "ge", "mdio"), + MPP_FUNCTION(3, "uart3", "txd")), + MPP_MODE(29, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "xg", "mdio"), + MPP_FUNCTION(2, "ge", "mdio"), + MPP_FUNCTION(3, "uart3", "rxd")), + MPP_MODE(30, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "xg", "mdio"), + MPP_FUNCTION(2, "ge", "mdio"), + MPP_FUNCTION(3, "ge", "mdio")), + MPP_MODE(31, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "xg", "mdio"), + MPP_FUNCTION(2, "ge", "mdio"), + MPP_FUNCTION(3, "ge", "mdio")), + MPP_MODE(32, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "uart0", "txd")), + MPP_MODE(33, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "uart0", "rxd"), + MPP_FUNCTION(2, "ptp", "clk1"), + MPP_FUNCTION(3, "ptp", "pulse")), + MPP_MODE(34, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge", "mdio"), + MPP_FUNCTION(2, "uart3", "rxd")), + MPP_MODE(35, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge", "mdio"), + MPP_FUNCTION(2, "uart3", "txd"), + MPP_FUNCTION(3, "pcie", "rstoutn")), + MPP_MODE(36, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ptp", "clk0_tp"), + MPP_FUNCTION(2, "ptp", "clk1_tp")), + MPP_MODE(37, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ptp", "pulse_tp"), + MPP_FUNCTION(2, "wd_int", NULL)), + MPP_MODE(38, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "synce", "clk_out0")), + MPP_MODE(39, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "synce", "clk_out1")), + MPP_MODE(40, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ptp", "pclk_out0"), + MPP_FUNCTION(2, "ptp", "pclk_out1")), + MPP_MODE(41, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ptp", "ref_clk"), + MPP_FUNCTION(2, "ptp", "clk1"), + MPP_FUNCTION(3, "ptp", "pulse"), + MPP_FUNCTION(4, "uart2", "txd"), + MPP_FUNCTION(5, "i2c1", "sck")), + MPP_MODE(42, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ptp", "clk0"), + MPP_FUNCTION(2, "ptp", "clk1"), + MPP_FUNCTION(3, "ptp", "pulse"), + MPP_FUNCTION(4, "uart2", "rxd"), + MPP_FUNCTION(5, "i2c1", "sda")), + MPP_MODE(43, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "led", "clk")), + MPP_MODE(44, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "led", "stb")), + MPP_MODE(45, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "led", "data")), +}; + +static struct mvebu_pinctrl_soc_info ac5_pinctrl_info; + +static const struct of_device_id ac5_pinctrl_of_match[] = { + { + .compatible = "marvell,ac5-pinctrl", + }, + { }, +}; + +static const struct mvebu_mpp_ctrl ac5_mpp_controls[] = { + MPP_FUNC_CTRL(0, 45, NULL, mvebu_mmio_mpp_ctrl), }; + +static struct pinctrl_gpio_range ac5_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 46), }; + +static int ac5_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &ac5_pinctrl_info; + + soc->variant = 0; /* no variants for ac5 */ + soc->controls = ac5_mpp_controls; + soc->ncontrols = ARRAY_SIZE(ac5_mpp_controls); + soc->gpioranges = ac5_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(ac5_mpp_gpio_ranges); + soc->modes = ac5_mpp_modes; + soc->nmodes = ac5_mpp_controls[0].npins; + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver ac5_pinctrl_driver = { + .driver = { + .name = "ac5-pinctrl", + .of_match_table = of_match_ptr(ac5_pinctrl_of_match), + }, + .probe = ac5_pinctrl_probe, +}; +builtin_platform_driver(ac5_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c new file mode 100644 index 000000000..a50c2183e --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada 370 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2012 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-mvebu.h" + +static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "uart0", "rxd")), + MPP_MODE(1, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "uart0", "txd")), + MPP_MODE(2, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "i2c0", "sck"), + MPP_FUNCTION(0x2, "uart0", "txd")), + MPP_MODE(3, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "i2c0", "sda"), + MPP_FUNCTION(0x2, "uart0", "rxd")), + MPP_MODE(4, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "vdd", "cpu-pd")), + MPP_MODE(5, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txclkout"), + MPP_FUNCTION(0x2, "uart1", "txd"), + MPP_FUNCTION(0x4, "spi1", "sck"), + MPP_FUNCTION(0x5, "audio", "mclk")), + MPP_MODE(6, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "txd0"), + MPP_FUNCTION(0x2, "sata0", "prsnt"), + MPP_FUNCTION(0x4, "tdm", "rst"), + MPP_FUNCTION(0x5, "audio", "sdo")), + MPP_MODE(7, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd1"), + MPP_FUNCTION(0x4, "tdm", "dtx"), + MPP_FUNCTION(0x5, "audio", "lrclk")), + MPP_MODE(8, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "txd2"), + MPP_FUNCTION(0x2, "uart0", "rts"), + MPP_FUNCTION(0x4, "tdm", "drx"), + MPP_FUNCTION(0x5, "audio", "bclk")), + MPP_MODE(9, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd3"), + MPP_FUNCTION(0x2, "uart1", "txd"), + MPP_FUNCTION(0x3, "sd0", "clk"), + MPP_FUNCTION(0x5, "audio", "spdifo")), + MPP_MODE(10, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "txctl"), + MPP_FUNCTION(0x2, "uart0", "cts"), + MPP_FUNCTION(0x4, "tdm", "fsync"), + MPP_FUNCTION(0x5, "audio", "sdi")), + MPP_MODE(11, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd0"), + MPP_FUNCTION(0x2, "uart1", "rxd"), + MPP_FUNCTION(0x3, "sd0", "cmd"), + MPP_FUNCTION(0x4, "spi0", "cs1"), + MPP_FUNCTION(0x5, "sata1", "prsnt"), + MPP_FUNCTION(0x6, "spi1", "cs1")), + MPP_MODE(12, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd1"), + MPP_FUNCTION(0x2, "i2c1", "sda"), + MPP_FUNCTION(0x3, "sd0", "d0"), + MPP_FUNCTION(0x4, "spi1", "cs0"), + MPP_FUNCTION(0x5, "audio", "spdifi")), + MPP_MODE(13, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd2"), + MPP_FUNCTION(0x2, "i2c1", "sck"), + MPP_FUNCTION(0x3, "sd0", "d1"), + MPP_FUNCTION(0x4, "tdm", "pclk"), + MPP_FUNCTION(0x5, "audio", "rmclk")), + MPP_MODE(14, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd3"), + MPP_FUNCTION(0x2, "pcie", "clkreq0"), + MPP_FUNCTION(0x3, "sd0", "d2"), + MPP_FUNCTION(0x4, "spi1", "mosi"), + MPP_FUNCTION(0x5, "spi0", "cs2")), + MPP_MODE(15, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxctl"), + MPP_FUNCTION(0x2, "pcie", "clkreq1"), + MPP_FUNCTION(0x3, "sd0", "d3"), + MPP_FUNCTION(0x4, "spi1", "miso"), + MPP_FUNCTION(0x5, "spi0", "cs3")), + MPP_MODE(16, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxclk"), + MPP_FUNCTION(0x2, "uart1", "rxd"), + MPP_FUNCTION(0x4, "tdm", "int"), + MPP_FUNCTION(0x5, "audio", "extclk")), + MPP_MODE(17, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge", "mdc")), + MPP_MODE(18, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge", "mdio")), + MPP_MODE(19, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "txclk"), + MPP_FUNCTION(0x2, "ge1", "txclkout"), + MPP_FUNCTION(0x4, "tdm", "pclk")), + MPP_MODE(20, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd4"), + MPP_FUNCTION(0x2, "ge1", "txd0")), + MPP_MODE(21, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd5"), + MPP_FUNCTION(0x2, "ge1", "txd1"), + MPP_FUNCTION(0x4, "uart1", "txd")), + MPP_MODE(22, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd6"), + MPP_FUNCTION(0x2, "ge1", "txd2"), + MPP_FUNCTION(0x4, "uart0", "rts")), + MPP_MODE(23, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "ge0", "txd7"), + MPP_FUNCTION(0x2, "ge1", "txd3"), + MPP_FUNCTION(0x4, "spi1", "mosi")), + MPP_MODE(24, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "col"), + MPP_FUNCTION(0x2, "ge1", "txctl"), + MPP_FUNCTION(0x4, "spi1", "cs0")), + MPP_MODE(25, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxerr"), + MPP_FUNCTION(0x2, "ge1", "rxd0"), + MPP_FUNCTION(0x4, "uart1", "rxd")), + MPP_MODE(26, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "crs"), + MPP_FUNCTION(0x2, "ge1", "rxd1"), + MPP_FUNCTION(0x4, "spi1", "miso")), + MPP_MODE(27, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd4"), + MPP_FUNCTION(0x2, "ge1", "rxd2"), + MPP_FUNCTION(0x4, "uart0", "cts")), + MPP_MODE(28, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd5"), + MPP_FUNCTION(0x2, "ge1", "rxd3")), + MPP_MODE(29, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd6"), + MPP_FUNCTION(0x2, "ge1", "rxctl"), + MPP_FUNCTION(0x4, "i2c1", "sda")), + MPP_MODE(30, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "ge0", "rxd7"), + MPP_FUNCTION(0x2, "ge1", "rxclk"), + MPP_FUNCTION(0x4, "i2c1", "sck")), + MPP_MODE(31, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x3, "tclk", NULL), + MPP_FUNCTION(0x4, "ge0", "txerr")), + MPP_MODE(32, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "spi0", "cs0")), + MPP_MODE(33, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "bootcs"), + MPP_FUNCTION(0x2, "spi0", "cs0")), + MPP_MODE(34, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "we0"), + MPP_FUNCTION(0x2, "spi0", "mosi")), + MPP_MODE(35, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "oe"), + MPP_FUNCTION(0x2, "spi0", "sck")), + MPP_MODE(36, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "a1"), + MPP_FUNCTION(0x2, "spi0", "miso")), + MPP_MODE(37, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "a0"), + MPP_FUNCTION(0x2, "sata0", "prsnt")), + MPP_MODE(38, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ready"), + MPP_FUNCTION(0x2, "uart1", "cts"), + MPP_FUNCTION(0x3, "uart0", "cts")), + MPP_MODE(39, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad0"), + MPP_FUNCTION(0x2, "audio", "spdifo")), + MPP_MODE(40, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad1"), + MPP_FUNCTION(0x2, "uart1", "rts"), + MPP_FUNCTION(0x3, "uart0", "rts")), + MPP_MODE(41, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad2"), + MPP_FUNCTION(0x2, "uart1", "rxd")), + MPP_MODE(42, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad3"), + MPP_FUNCTION(0x2, "uart1", "txd")), + MPP_MODE(43, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad4"), + MPP_FUNCTION(0x2, "audio", "bclk")), + MPP_MODE(44, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad5"), + MPP_FUNCTION(0x2, "audio", "mclk")), + MPP_MODE(45, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad6"), + MPP_FUNCTION(0x2, "audio", "lrclk")), + MPP_MODE(46, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad7"), + MPP_FUNCTION(0x2, "audio", "sdo")), + MPP_MODE(47, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad8"), + MPP_FUNCTION(0x3, "sd0", "clk"), + MPP_FUNCTION(0x5, "audio", "spdifo")), + MPP_MODE(48, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad9"), + MPP_FUNCTION(0x2, "uart0", "rts"), + MPP_FUNCTION(0x3, "sd0", "cmd"), + MPP_FUNCTION(0x4, "sata1", "prsnt"), + MPP_FUNCTION(0x5, "spi0", "cs1")), + MPP_MODE(49, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad10"), + MPP_FUNCTION(0x2, "pcie", "clkreq1"), + MPP_FUNCTION(0x3, "sd0", "d0"), + MPP_FUNCTION(0x4, "spi1", "cs0"), + MPP_FUNCTION(0x5, "audio", "spdifi")), + MPP_MODE(50, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad11"), + MPP_FUNCTION(0x2, "uart0", "cts"), + MPP_FUNCTION(0x3, "sd0", "d1"), + MPP_FUNCTION(0x4, "spi1", "miso"), + MPP_FUNCTION(0x5, "audio", "rmclk")), + MPP_MODE(51, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad12"), + MPP_FUNCTION(0x2, "i2c1", "sda"), + MPP_FUNCTION(0x3, "sd0", "d2"), + MPP_FUNCTION(0x4, "spi1", "mosi")), + MPP_MODE(52, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad13"), + MPP_FUNCTION(0x2, "i2c1", "sck"), + MPP_FUNCTION(0x3, "sd0", "d3"), + MPP_FUNCTION(0x4, "spi1", "sck")), + MPP_MODE(53, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad14"), + MPP_FUNCTION(0x2, "sd0", "clk"), + MPP_FUNCTION(0x3, "tdm", "pclk"), + MPP_FUNCTION(0x4, "spi0", "cs2"), + MPP_FUNCTION(0x5, "pcie", "clkreq1")), + MPP_MODE(54, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ad15"), + MPP_FUNCTION(0x3, "tdm", "dtx")), + MPP_MODE(55, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "cs1"), + MPP_FUNCTION(0x2, "uart1", "txd"), + MPP_FUNCTION(0x3, "tdm", "rst"), + MPP_FUNCTION(0x4, "sata1", "prsnt"), + MPP_FUNCTION(0x5, "sata0", "prsnt")), + MPP_MODE(56, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "cs2"), + MPP_FUNCTION(0x2, "uart1", "cts"), + MPP_FUNCTION(0x3, "uart0", "cts"), + MPP_FUNCTION(0x4, "spi0", "cs3"), + MPP_FUNCTION(0x5, "pcie", "clkreq0"), + MPP_FUNCTION(0x6, "spi1", "cs1")), + MPP_MODE(57, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "cs3"), + MPP_FUNCTION(0x2, "uart1", "rxd"), + MPP_FUNCTION(0x3, "tdm", "fsync"), + MPP_FUNCTION(0x4, "sata0", "prsnt"), + MPP_FUNCTION(0x5, "audio", "sdo")), + MPP_MODE(58, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "cs0"), + MPP_FUNCTION(0x2, "uart1", "rts"), + MPP_FUNCTION(0x3, "tdm", "int"), + MPP_FUNCTION(0x5, "audio", "extclk"), + MPP_FUNCTION(0x6, "uart0", "rts")), + MPP_MODE(59, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "ale0"), + MPP_FUNCTION(0x2, "uart1", "rts"), + MPP_FUNCTION(0x3, "uart0", "rts"), + MPP_FUNCTION(0x5, "audio", "bclk")), + MPP_MODE(60, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ale1"), + MPP_FUNCTION(0x2, "uart1", "rxd"), + MPP_FUNCTION(0x3, "sata0", "prsnt"), + MPP_FUNCTION(0x4, "pcie", "rstout"), + MPP_FUNCTION(0x5, "audio", "sdi")), + MPP_MODE(61, + MPP_FUNCTION(0x0, "gpo", NULL), + MPP_FUNCTION(0x1, "dev", "we1"), + MPP_FUNCTION(0x2, "uart1", "txd"), + MPP_FUNCTION(0x5, "audio", "lrclk")), + MPP_MODE(62, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "a2"), + MPP_FUNCTION(0x2, "uart1", "cts"), + MPP_FUNCTION(0x3, "tdm", "drx"), + MPP_FUNCTION(0x4, "pcie", "clkreq0"), + MPP_FUNCTION(0x5, "audio", "mclk"), + MPP_FUNCTION(0x6, "uart0", "cts")), + MPP_MODE(63, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "spi0", "sck"), + MPP_FUNCTION(0x2, "tclk", NULL)), + MPP_MODE(64, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "spi0", "miso"), + MPP_FUNCTION(0x2, "spi0", "cs1")), + MPP_MODE(65, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "spi0", "mosi"), + MPP_FUNCTION(0x2, "spi0", "cs2")), +}; + +static struct mvebu_pinctrl_soc_info armada_370_pinctrl_info; + +static const struct of_device_id armada_370_pinctrl_of_match[] = { + { .compatible = "marvell,mv88f6710-pinctrl" }, + { }, +}; + +static const struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = { + MPP_FUNC_CTRL(0, 65, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 32), + MPP_GPIO_RANGE(2, 64, 64, 2), +}; + +static int armada_370_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info; + + soc->variant = 0; /* no variants for Armada 370 */ + soc->controls = mv88f6710_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv88f6710_mpp_controls); + soc->modes = mv88f6710_mpp_modes; + soc->nmodes = ARRAY_SIZE(mv88f6710_mpp_modes); + soc->gpioranges = mv88f6710_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv88f6710_mpp_gpio_ranges); + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver armada_370_pinctrl_driver = { + .driver = { + .name = "armada-370-pinctrl", + .of_match_table = armada_370_pinctrl_of_match, + }, + .probe = armada_370_pinctrl_probe, +}; +builtin_platform_driver(armada_370_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-375.c b/drivers/pinctrl/mvebu/pinctrl-armada-375.c new file mode 100644 index 000000000..64e2096a0 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-375.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada 375 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2012 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-mvebu.h" + +static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad2"), + MPP_FUNCTION(0x2, "spi0", "cs1"), + MPP_FUNCTION(0x3, "spi1", "cs1"), + MPP_FUNCTION(0x5, "nand", "io2")), + MPP_MODE(1, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad3"), + MPP_FUNCTION(0x2, "spi0", "mosi"), + MPP_FUNCTION(0x3, "spi1", "mosi"), + MPP_FUNCTION(0x5, "nand", "io3")), + MPP_MODE(2, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad4"), + MPP_FUNCTION(0x2, "ptp", "evreq"), + MPP_FUNCTION(0x3, "led", "c0"), + MPP_FUNCTION(0x4, "audio", "sdi"), + MPP_FUNCTION(0x5, "nand", "io4"), + MPP_FUNCTION(0x6, "spi1", "mosi")), + MPP_MODE(3, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad5"), + MPP_FUNCTION(0x2, "ptp", "trig"), + MPP_FUNCTION(0x3, "led", "p3"), + MPP_FUNCTION(0x4, "audio", "mclk"), + MPP_FUNCTION(0x5, "nand", "io5"), + MPP_FUNCTION(0x6, "spi1", "miso")), + MPP_MODE(4, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad6"), + MPP_FUNCTION(0x2, "spi0", "miso"), + MPP_FUNCTION(0x3, "spi1", "miso"), + MPP_FUNCTION(0x5, "nand", "io6")), + MPP_MODE(5, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad7"), + MPP_FUNCTION(0x2, "spi0", "cs2"), + MPP_FUNCTION(0x3, "spi1", "cs2"), + MPP_FUNCTION(0x5, "nand", "io7"), + MPP_FUNCTION(0x6, "spi1", "miso")), + MPP_MODE(6, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad0"), + MPP_FUNCTION(0x3, "led", "p1"), + MPP_FUNCTION(0x4, "audio", "lrclk"), + MPP_FUNCTION(0x5, "nand", "io0")), + MPP_MODE(7, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ad1"), + MPP_FUNCTION(0x2, "ptp", "clk"), + MPP_FUNCTION(0x3, "led", "p2"), + MPP_FUNCTION(0x4, "audio", "extclk"), + MPP_FUNCTION(0x5, "nand", "io1")), + MPP_MODE(8, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "bootcs"), + MPP_FUNCTION(0x2, "spi0", "cs0"), + MPP_FUNCTION(0x3, "spi1", "cs0"), + MPP_FUNCTION(0x5, "nand", "ce")), + MPP_MODE(9, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "spi0", "sck"), + MPP_FUNCTION(0x3, "spi1", "sck"), + MPP_FUNCTION(0x5, "nand", "we")), + MPP_MODE(10, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "dram", "vttctrl"), + MPP_FUNCTION(0x3, "led", "c1"), + MPP_FUNCTION(0x5, "nand", "re"), + MPP_FUNCTION(0x6, "spi1", "sck")), + MPP_MODE(11, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "a0"), + MPP_FUNCTION(0x3, "led", "c2"), + MPP_FUNCTION(0x4, "audio", "sdo"), + MPP_FUNCTION(0x5, "nand", "cle")), + MPP_MODE(12, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "a1"), + MPP_FUNCTION(0x4, "audio", "bclk"), + MPP_FUNCTION(0x5, "nand", "ale")), + MPP_MODE(13, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "dev", "ready"), + MPP_FUNCTION(0x2, "pcie0", "rstout"), + MPP_FUNCTION(0x3, "pcie1", "rstout"), + MPP_FUNCTION(0x5, "nand", "rb"), + MPP_FUNCTION(0x6, "spi1", "mosi")), + MPP_MODE(14, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "i2c0", "sda"), + MPP_FUNCTION(0x3, "uart1", "txd")), + MPP_MODE(15, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "i2c0", "sck"), + MPP_FUNCTION(0x3, "uart1", "rxd")), + MPP_MODE(16, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "uart0", "txd")), + MPP_MODE(17, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "uart0", "rxd")), + MPP_MODE(18, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "int")), + MPP_MODE(19, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "rst")), + MPP_MODE(20, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "pclk")), + MPP_MODE(21, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "fsync")), + MPP_MODE(22, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "drx")), + MPP_MODE(23, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "tdm", "dtx")), + MPP_MODE(24, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p0"), + MPP_FUNCTION(0x2, "ge1", "rxd0"), + MPP_FUNCTION(0x3, "sd", "cmd"), + MPP_FUNCTION(0x4, "uart0", "rts"), + MPP_FUNCTION(0x5, "spi0", "cs0"), + MPP_FUNCTION(0x6, "dev", "cs1")), + MPP_MODE(25, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p2"), + MPP_FUNCTION(0x2, "ge1", "rxd1"), + MPP_FUNCTION(0x3, "sd", "d0"), + MPP_FUNCTION(0x4, "uart0", "cts"), + MPP_FUNCTION(0x5, "spi0", "mosi"), + MPP_FUNCTION(0x6, "dev", "cs2")), + MPP_MODE(26, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie0", "clkreq"), + MPP_FUNCTION(0x2, "ge1", "rxd2"), + MPP_FUNCTION(0x3, "sd", "d2"), + MPP_FUNCTION(0x4, "uart1", "rts"), + MPP_FUNCTION(0x5, "spi0", "cs1"), + MPP_FUNCTION(0x6, "led", "c1")), + MPP_MODE(27, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie1", "clkreq"), + MPP_FUNCTION(0x2, "ge1", "rxd3"), + MPP_FUNCTION(0x3, "sd", "d1"), + MPP_FUNCTION(0x4, "uart1", "cts"), + MPP_FUNCTION(0x5, "spi0", "miso"), + MPP_FUNCTION(0x6, "led", "c2")), + MPP_MODE(28, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p3"), + MPP_FUNCTION(0x2, "ge1", "txctl"), + MPP_FUNCTION(0x3, "sd", "clk"), + MPP_FUNCTION(0x5, "dram", "vttctrl")), + MPP_MODE(29, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie1", "clkreq"), + MPP_FUNCTION(0x2, "ge1", "rxclk"), + MPP_FUNCTION(0x3, "sd", "d3"), + MPP_FUNCTION(0x5, "spi0", "sck"), + MPP_FUNCTION(0x6, "pcie0", "rstout")), + MPP_MODE(30, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "txd0"), + MPP_FUNCTION(0x3, "spi1", "cs0"), + MPP_FUNCTION(0x5, "led", "p3"), + MPP_FUNCTION(0x6, "ptp", "evreq")), + MPP_MODE(31, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "txd1"), + MPP_FUNCTION(0x3, "spi1", "mosi"), + MPP_FUNCTION(0x5, "led", "p0")), + MPP_MODE(32, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "txd2"), + MPP_FUNCTION(0x3, "spi1", "sck"), + MPP_FUNCTION(0x4, "ptp", "trig"), + MPP_FUNCTION(0x5, "led", "c0")), + MPP_MODE(33, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "txd3"), + MPP_FUNCTION(0x3, "spi1", "miso"), + MPP_FUNCTION(0x5, "led", "p2")), + MPP_MODE(34, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "txclkout"), + MPP_FUNCTION(0x3, "spi1", "sck"), + MPP_FUNCTION(0x5, "led", "c1")), + MPP_MODE(35, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge1", "rxctl"), + MPP_FUNCTION(0x3, "spi1", "cs1"), + MPP_FUNCTION(0x4, "spi0", "cs2"), + MPP_FUNCTION(0x5, "led", "p1")), + MPP_MODE(36, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie0", "clkreq"), + MPP_FUNCTION(0x5, "led", "c2")), + MPP_MODE(37, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie0", "clkreq"), + MPP_FUNCTION(0x2, "tdm", "int"), + MPP_FUNCTION(0x4, "ge", "mdc")), + MPP_MODE(38, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie1", "clkreq"), + MPP_FUNCTION(0x4, "ge", "mdio")), + MPP_MODE(39, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "ref", "clkout"), + MPP_FUNCTION(0x5, "led", "p3")), + MPP_MODE(40, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "uart1", "txd"), + MPP_FUNCTION(0x5, "led", "p0")), + MPP_MODE(41, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "uart1", "rxd"), + MPP_FUNCTION(0x5, "led", "p1")), + MPP_MODE(42, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x3, "spi1", "cs2"), + MPP_FUNCTION(0x4, "led", "c0"), + MPP_FUNCTION(0x6, "ptp", "clk")), + MPP_MODE(43, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "sata0", "prsnt"), + MPP_FUNCTION(0x4, "dram", "vttctrl"), + MPP_FUNCTION(0x5, "led", "c1")), + MPP_MODE(44, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "sata0", "prsnt")), + MPP_MODE(45, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "spi0", "cs2"), + MPP_FUNCTION(0x4, "pcie0", "rstout"), + MPP_FUNCTION(0x5, "led", "c2"), + MPP_FUNCTION(0x6, "spi1", "cs2")), + MPP_MODE(46, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p0"), + MPP_FUNCTION(0x2, "ge0", "txd0"), + MPP_FUNCTION(0x3, "ge1", "txd0"), + MPP_FUNCTION(0x6, "dev", "we1")), + MPP_MODE(47, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p1"), + MPP_FUNCTION(0x2, "ge0", "txd1"), + MPP_FUNCTION(0x3, "ge1", "txd1"), + MPP_FUNCTION(0x5, "ptp", "trig"), + MPP_FUNCTION(0x6, "dev", "ale0")), + MPP_MODE(48, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p2"), + MPP_FUNCTION(0x2, "ge0", "txd2"), + MPP_FUNCTION(0x3, "ge1", "txd2"), + MPP_FUNCTION(0x6, "dev", "ale1")), + MPP_MODE(49, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "p3"), + MPP_FUNCTION(0x2, "ge0", "txd3"), + MPP_FUNCTION(0x3, "ge1", "txd3"), + MPP_FUNCTION(0x6, "dev", "a2")), + MPP_MODE(50, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "c0"), + MPP_FUNCTION(0x2, "ge0", "rxd0"), + MPP_FUNCTION(0x3, "ge1", "rxd0"), + MPP_FUNCTION(0x5, "ptp", "evreq"), + MPP_FUNCTION(0x6, "dev", "ad12")), + MPP_MODE(51, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "c1"), + MPP_FUNCTION(0x2, "ge0", "rxd1"), + MPP_FUNCTION(0x3, "ge1", "rxd1"), + MPP_FUNCTION(0x6, "dev", "ad8")), + MPP_MODE(52, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "led", "c2"), + MPP_FUNCTION(0x2, "ge0", "rxd2"), + MPP_FUNCTION(0x3, "ge1", "rxd2"), + MPP_FUNCTION(0x5, "i2c0", "sda"), + MPP_FUNCTION(0x6, "dev", "ad9")), + MPP_MODE(53, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie1", "rstout"), + MPP_FUNCTION(0x2, "ge0", "rxd3"), + MPP_FUNCTION(0x3, "ge1", "rxd3"), + MPP_FUNCTION(0x5, "i2c0", "sck"), + MPP_FUNCTION(0x6, "dev", "ad10")), + MPP_MODE(54, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "pcie0", "rstout"), + MPP_FUNCTION(0x2, "ge0", "rxctl"), + MPP_FUNCTION(0x3, "ge1", "rxctl"), + MPP_FUNCTION(0x6, "dev", "ad11")), + MPP_MODE(55, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge0", "rxclk"), + MPP_FUNCTION(0x3, "ge1", "rxclk"), + MPP_FUNCTION(0x6, "dev", "cs0")), + MPP_MODE(56, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge0", "txclkout"), + MPP_FUNCTION(0x3, "ge1", "txclkout"), + MPP_FUNCTION(0x6, "dev", "oe")), + MPP_MODE(57, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ge0", "txctl"), + MPP_FUNCTION(0x3, "ge1", "txctl"), + MPP_FUNCTION(0x6, "dev", "we0")), + MPP_MODE(58, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "led", "c0")), + MPP_MODE(59, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x4, "led", "c1")), + MPP_MODE(60, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "uart1", "txd"), + MPP_FUNCTION(0x4, "led", "c2"), + MPP_FUNCTION(0x6, "dev", "ad13")), + MPP_MODE(61, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "i2c1", "sda"), + MPP_FUNCTION(0x2, "uart1", "rxd"), + MPP_FUNCTION(0x3, "spi1", "cs2"), + MPP_FUNCTION(0x4, "led", "p0"), + MPP_FUNCTION(0x6, "dev", "ad14")), + MPP_MODE(62, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "i2c1", "sck"), + MPP_FUNCTION(0x4, "led", "p1"), + MPP_FUNCTION(0x6, "dev", "ad15")), + MPP_MODE(63, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ptp", "trig"), + MPP_FUNCTION(0x4, "led", "p2"), + MPP_FUNCTION(0x6, "dev", "burst/last")), + MPP_MODE(64, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "dram", "vttctrl"), + MPP_FUNCTION(0x4, "led", "p3")), + MPP_MODE(65, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x1, "sata1", "prsnt")), + MPP_MODE(66, + MPP_FUNCTION(0x0, "gpio", NULL), + MPP_FUNCTION(0x2, "ptp", "evreq"), + MPP_FUNCTION(0x4, "spi1", "cs3"), + MPP_FUNCTION(0x5, "pcie0", "rstout"), + MPP_FUNCTION(0x6, "dev", "cs3")), +}; + +static struct mvebu_pinctrl_soc_info armada_375_pinctrl_info; + +static const struct of_device_id armada_375_pinctrl_of_match[] = { + { .compatible = "marvell,mv88f6720-pinctrl" }, + { }, +}; + +static const struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = { + MPP_FUNC_CTRL(0, 69, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 32), + MPP_GPIO_RANGE(2, 64, 64, 3), +}; + +static int armada_375_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_375_pinctrl_info; + + soc->variant = 0; /* no variants for Armada 375 */ + soc->controls = mv88f6720_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv88f6720_mpp_controls); + soc->modes = mv88f6720_mpp_modes; + soc->nmodes = ARRAY_SIZE(mv88f6720_mpp_modes); + soc->gpioranges = mv88f6720_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv88f6720_mpp_gpio_ranges); + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver armada_375_pinctrl_driver = { + .driver = { + .name = "armada-375-pinctrl", + .of_match_table = of_match_ptr(armada_375_pinctrl_of_match), + }, + .probe = armada_375_pinctrl_probe, +}; +builtin_platform_driver(armada_375_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c new file mode 100644 index 000000000..81dfbd5e7 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -0,0 +1,1184 @@ +/* + * Marvell 37xx SoC pinctrl driver + * + * Copyright (C) 2017 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2 or later. This program is licensed "as is" + * without any warranty of any kind, whether express or implied. + */ + +#include <linux/gpio/driver.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/string_helpers.h> + +#include "../pinctrl-utils.h" + +#define OUTPUT_EN 0x0 +#define INPUT_VAL 0x10 +#define OUTPUT_VAL 0x18 +#define OUTPUT_CTL 0x20 +#define SELECTION 0x30 + +#define IRQ_EN 0x0 +#define IRQ_POL 0x08 +#define IRQ_STATUS 0x10 +#define IRQ_WKUP 0x18 + +#define NB_FUNCS 3 +#define GPIO_PER_REG 32 + +/** + * struct armada_37xx_pin_group: represents group of pins of a pinmux function. + * The pins of a pinmux groups are composed of one or two groups of contiguous + * pins. + * @name: Name of the pin group, used to lookup the group. + * @start_pin: Index of the first pin of the main range of pins belonging to + * the group + * @npins: Number of pins included in the first range + * @reg_mask: Bit mask matching the group in the selection register + * @val: Value to write to the registers for a given function + * @extra_pin: Index of the first pin of the optional second range of pins + * belonging to the group + * @extra_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; + unsigned int start_pin; + unsigned int npins; + u32 reg_mask; + u32 val[NB_FUNCS]; + unsigned int extra_pin; + unsigned int extra_npins; + const char *funcs[NB_FUNCS]; + unsigned int *pins; +}; + +struct armada_37xx_pin_data { + u8 nr_pins; + char *name; + struct armada_37xx_pin_group *groups; + int ngroups; +}; + +struct armada_37xx_pmx_func { + const char *name; + const char **groups; + unsigned int ngroups; +}; + +struct armada_37xx_pm_state { + u32 out_en_l; + u32 out_en_h; + u32 out_val_l; + u32 out_val_h; + u32 irq_en_l; + u32 irq_en_h; + u32 irq_pol_l; + u32 irq_pol_h; + u32 selection; +}; + +struct armada_37xx_pinctrl { + struct regmap *regmap; + void __iomem *base; + const struct armada_37xx_pin_data *data; + struct device *dev; + struct gpio_chip gpio_chip; + raw_spinlock_t irq_lock; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + struct armada_37xx_pin_group *groups; + unsigned int ngroups; + struct armada_37xx_pmx_func *funcs; + unsigned int nfuncs; + struct armada_37xx_pm_state pm; +}; + +#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, \ + .start_pin = _start, \ + .npins = _nr, \ + .reg_mask = _mask, \ + .val = {0, _mask}, \ + .funcs = {_func1, "gpio"} \ + } + +#define PIN_GRP_GPIO_2(_name, _start, _nr, _mask, _val1, _val2, _func1) \ + { \ + .name = _name, \ + .start_pin = _start, \ + .npins = _nr, \ + .reg_mask = _mask, \ + .val = {_val1, _val2}, \ + .funcs = {_func1, "gpio"} \ + } + +#define PIN_GRP_GPIO_3(_name, _start, _nr, _mask, _v1, _v2, _v3, _f1, _f2) \ + { \ + .name = _name, \ + .start_pin = _start, \ + .npins = _nr, \ + .reg_mask = _mask, \ + .val = {_v1, _v2, _v3}, \ + .funcs = {_f1, _f2, "gpio"} \ + } + +#define PIN_GRP_EXTRA(_name, _start, _nr, _mask, _v1, _v2, _start2, _nr2, \ + _f1, _f2) \ + { \ + .name = _name, \ + .start_pin = _start, \ + .npins = _nr, \ + .reg_mask = _mask, \ + .val = {_v1, _v2}, \ + .extra_pin = _start2, \ + .extra_npins = _nr2, \ + .funcs = {_f1, _f2} \ + } + +static struct armada_37xx_pin_group armada_37xx_nb_groups[] = { + PIN_GRP_GPIO("jtag", 20, 5, BIT(0), "jtag"), + PIN_GRP_GPIO("sdio0", 8, 3, BIT(1), "sdio"), + PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"), + PIN_GRP_GPIO_3("pwm0", 11, 1, BIT(3) | BIT(20), 0, BIT(20), BIT(3), + "pwm", "led"), + PIN_GRP_GPIO_3("pwm1", 12, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4), + "pwm", "led"), + PIN_GRP_GPIO_3("pwm2", 13, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5), + "pwm", "led"), + PIN_GRP_GPIO_3("pwm3", 14, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6), + "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"), + PIN_GRP_GPIO_2("spi_cs2", 18, 1, BIT(13) | BIT(19), 0, BIT(13), "spi"), + PIN_GRP_GPIO_2("spi_cs3", 19, 1, BIT(14) | BIT(19), 0, BIT(14), "spi"), + PIN_GRP_GPIO("onewire", 4, 1, BIT(16), "onewire"), + PIN_GRP_GPIO("uart1", 25, 2, BIT(17), "uart"), + PIN_GRP_GPIO("spi_quad", 15, 2, BIT(18), "spi"), + PIN_GRP_EXTRA("uart2", 9, 2, BIT(1) | BIT(13) | BIT(14) | BIT(19), + BIT(1) | BIT(13) | BIT(14), BIT(1) | BIT(19), + 18, 2, "gpio", "uart"), +}; + +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, 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, 1, BIT(11), "ptp"), + PIN_GRP_GPIO_3("ptp_clk", 21, 1, BIT(6) | BIT(12), 0, BIT(6), BIT(12), + "ptp", "mii"), + PIN_GRP_GPIO_3("ptp_trig", 22, 1, BIT(7) | BIT(13), 0, BIT(7), BIT(13), + "ptp", "mii"), + PIN_GRP_GPIO_3("mii_col", 23, 1, BIT(8) | BIT(14), 0, BIT(8), BIT(14), + "mii", "mii_err"), +}; + +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), +}; + +static const struct armada_37xx_pin_data armada_37xx_pin_sb = { + .nr_pins = 30, + .name = "GPIO2", + .groups = armada_37xx_sb_groups, + .ngroups = ARRAY_SIZE(armada_37xx_sb_groups), +}; + +static inline void armada_37xx_update_reg(unsigned int *reg, + unsigned int *offset) +{ + /* We never have more than 2 registers */ + if (*offset >= GPIO_PER_REG) { + *offset -= GPIO_PER_REG; + *reg += sizeof(u32); + } +} + +static struct armada_37xx_pin_group *armada_37xx_find_next_grp_by_pin( + struct armada_37xx_pinctrl *info, int pin, int *grp) +{ + while (*grp < info->ngroups) { + struct armada_37xx_pin_group *group = &info->groups[*grp]; + int j; + + *grp = *grp + 1; + for (j = 0; j < (group->npins + group->extra_npins); j++) + if (group->pins[j] == pin) + return group; + } + return NULL; +} + +static int armada_37xx_pin_config_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned long *config) +{ + return -ENOTSUPP; +} + +static int armada_37xx_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, unsigned long *configs, + unsigned int num_configs) +{ + return -ENOTSUPP; +} + +static const struct pinconf_ops armada_37xx_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = armada_37xx_pin_config_group_get, + .pin_config_group_set = armada_37xx_pin_config_group_set, +}; + +static int armada_37xx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *armada_37xx_get_group_name(struct pinctrl_dev *pctldev, + unsigned int group) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[group].name; +} + +static int armada_37xx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *npins) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins + + info->groups[selector].extra_npins; + + return 0; +} + +static const struct pinctrl_ops armada_37xx_pctrl_ops = { + .get_groups_count = armada_37xx_get_groups_count, + .get_group_name = armada_37xx_get_group_name, + .get_group_pins = armada_37xx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_free_map, +}; + +/* + * Pinmux_ops handling + */ + +static int armada_37xx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfuncs; +} + +static const char *armada_37xx_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->funcs[selector].name; +} + +static int armada_37xx_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->funcs[selector].groups; + *num_groups = info->funcs[selector].ngroups; + + return 0; +} + +static int armada_37xx_pmx_set_by_name(struct pinctrl_dev *pctldev, + const char *name, + struct armada_37xx_pin_group *grp) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = info->dev; + unsigned int reg = SELECTION; + unsigned int mask = grp->reg_mask; + int func, val; + + dev_dbg(dev, "enable function %s group %s\n", name, grp->name); + + func = match_string(grp->funcs, NB_FUNCS, name); + if (func < 0) + return -ENOTSUPP; + + val = grp->val[func]; + + return regmap_update_bits(info->regmap, reg, mask, val); +} + +static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned int group) +{ + + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct armada_37xx_pin_group *grp = &info->groups[group]; + const char *name = info->funcs[selector].name; + + return armada_37xx_pmx_set_by_name(pctldev, name, grp); +} + +static inline void armada_37xx_irq_update_reg(unsigned int *reg, + struct irq_data *d) +{ + int offset = irqd_to_hwirq(d); + + armada_37xx_update_reg(reg, &offset); +} + +static int armada_37xx_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = OUTPUT_EN; + unsigned int mask; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + + return regmap_update_bits(info->regmap, reg, mask, 0); +} + +static int armada_37xx_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = OUTPUT_EN; + unsigned int val, mask; + int ret; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + ret = regmap_read(info->regmap, reg, &val); + if (ret) + return ret; + + if (val & mask) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int armada_37xx_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int en_offset = offset; + unsigned int reg = OUTPUT_VAL; + unsigned int mask, val; + int ret; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + val = value ? mask : 0; + + ret = regmap_update_bits(info->regmap, reg, mask, val); + if (ret) + return ret; + + reg = OUTPUT_EN; + armada_37xx_update_reg(®, &en_offset); + + return regmap_update_bits(info->regmap, reg, mask, mask); +} + +static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = INPUT_VAL; + unsigned int val, mask; + int ret; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + + ret = regmap_read(info->regmap, reg, &val); + if (ret) + return ret; + + return (val & mask) != 0; +} + +static int armada_37xx_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + unsigned int reg = OUTPUT_VAL; + unsigned int mask, val; + + armada_37xx_update_reg(®, &offset); + mask = BIT(offset); + val = value ? mask : 0; + + return regmap_update_bits(info->regmap, reg, mask, val); +} + +static int armada_37xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = range->gc; + int ret; + + dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", + offset, range->name, offset, input ? "input" : "output"); + + if (input) + ret = armada_37xx_gpio_direction_input(chip, offset); + else + ret = armada_37xx_gpio_direction_output(chip, offset, 0); + + return ret; +} + +static int armada_37xx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct armada_37xx_pin_group *group; + int grp = 0; + int ret; + + dev_dbg(info->dev, "requesting gpio %d\n", offset); + + while ((group = armada_37xx_find_next_grp_by_pin(info, offset, &grp))) { + ret = armada_37xx_pmx_set_by_name(pctldev, "gpio", group); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinmux_ops armada_37xx_pmx_ops = { + .get_functions_count = armada_37xx_pmx_get_funcs_count, + .get_function_name = armada_37xx_pmx_get_func_name, + .get_function_groups = armada_37xx_pmx_get_groups, + .set_mux = armada_37xx_pmx_set, + .gpio_request_enable = armada_37xx_gpio_request_enable, + .gpio_set_direction = armada_37xx_pmx_gpio_set_direction, +}; + +static const struct gpio_chip armada_37xx_gpiolib_chip = { + .request = gpiochip_generic_request, + .free = gpiochip_generic_free, + .set = armada_37xx_gpio_set, + .get = armada_37xx_gpio_get, + .get_direction = armada_37xx_gpio_get_direction, + .direction_input = armada_37xx_gpio_direction_input, + .direction_output = armada_37xx_gpio_direction_output, + .owner = THIS_MODULE, +}; + +static void armada_37xx_irq_ack(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + u32 reg = IRQ_STATUS; + unsigned long flags; + + armada_37xx_irq_update_reg(®, d); + raw_spin_lock_irqsave(&info->irq_lock, flags); + writel(d->mask, info->base + reg); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); +} + +static void armada_37xx_irq_mask(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + u32 val, reg = IRQ_EN; + unsigned long flags; + + armada_37xx_irq_update_reg(®, d); + raw_spin_lock_irqsave(&info->irq_lock, flags); + val = readl(info->base + reg); + writel(val & ~d->mask, info->base + reg); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + gpiochip_disable_irq(chip, irqd_to_hwirq(d)); +} + +static void armada_37xx_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + u32 val, reg = IRQ_EN; + unsigned long flags; + + gpiochip_enable_irq(chip, irqd_to_hwirq(d)); + armada_37xx_irq_update_reg(®, d); + raw_spin_lock_irqsave(&info->irq_lock, flags); + val = readl(info->base + reg); + writel(val | d->mask, info->base + reg); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); +} + +static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + u32 val, reg = IRQ_WKUP; + unsigned long flags; + + armada_37xx_irq_update_reg(®, d); + raw_spin_lock_irqsave(&info->irq_lock, flags); + val = readl(info->base + reg); + if (on) + val |= (BIT(d->hwirq % GPIO_PER_REG)); + else + val &= ~(BIT(d->hwirq % GPIO_PER_REG)); + writel(val, info->base + reg); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + + return 0; +} + +static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + u32 val, reg = IRQ_POL; + unsigned long flags; + + raw_spin_lock_irqsave(&info->irq_lock, flags); + armada_37xx_irq_update_reg(®, d); + val = readl(info->base + reg); + switch (type) { + case IRQ_TYPE_EDGE_RISING: + val &= ~(BIT(d->hwirq % GPIO_PER_REG)); + break; + case IRQ_TYPE_EDGE_FALLING: + val |= (BIT(d->hwirq % GPIO_PER_REG)); + break; + case IRQ_TYPE_EDGE_BOTH: { + u32 in_val, in_reg = INPUT_VAL; + + armada_37xx_irq_update_reg(&in_reg, d); + regmap_read(info->regmap, in_reg, &in_val); + + /* Set initial polarity based on current input level. */ + if (in_val & BIT(d->hwirq % GPIO_PER_REG)) + val |= BIT(d->hwirq % GPIO_PER_REG); /* falling */ + else + val &= ~(BIT(d->hwirq % GPIO_PER_REG)); /* rising */ + break; + } + default: + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + return -EINVAL; + } + writel(val, info->base + reg); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + + return 0; +} + +static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info, + u32 pin_idx) +{ + u32 reg_idx = pin_idx / GPIO_PER_REG; + u32 bit_num = pin_idx % GPIO_PER_REG; + unsigned long flags; + u32 p, l; + int ret; + + regmap_read(info->regmap, INPUT_VAL + 4*reg_idx, &l); + + raw_spin_lock_irqsave(&info->irq_lock, flags); + p = readl(info->base + IRQ_POL + 4 * reg_idx); + if ((p ^ l) & (1 << bit_num)) { + /* + * For the gpios which are used for both-edge irqs, when their + * interrupts happen, their input levels are changed, + * yet their interrupt polarities are kept in old values, we + * should synchronize their interrupt polarities; for example, + * at first a gpio's input level is low and its interrupt + * polarity control is "Detect rising edge", then the gpio has + * a interrupt , its level turns to high, we should change its + * polarity control to "Detect falling edge" correspondingly. + */ + p ^= 1 << bit_num; + writel(p, info->base + IRQ_POL + 4 * reg_idx); + ret = 0; + } else { + /* Spurious irq */ + ret = -1; + } + + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + return ret; +} + +static void armada_37xx_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct armada_37xx_pinctrl *info = gpiochip_get_data(gc); + struct irq_domain *d = gc->irq.domain; + int i; + + chained_irq_enter(chip, desc); + for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) { + u32 status; + unsigned long flags; + + raw_spin_lock_irqsave(&info->irq_lock, flags); + status = readl_relaxed(info->base + IRQ_STATUS + 4 * i); + /* Manage only the interrupt that was enabled */ + status &= readl_relaxed(info->base + IRQ_EN + 4 * i); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + while (status) { + u32 hwirq = ffs(status) - 1; + u32 virq = irq_find_mapping(d, hwirq + + i * GPIO_PER_REG); + u32 t = irq_get_trigger_type(virq); + + if ((t & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + /* Swap polarity (race with GPIO line) */ + if (armada_37xx_edge_both_irq_swap_pol(info, + hwirq + i * GPIO_PER_REG)) { + /* + * For spurious irq, which gpio level + * is not as expected after incoming + * edge, just ack the gpio irq. + */ + writel(1 << hwirq, + info->base + + IRQ_STATUS + 4 * i); + goto update_status; + } + } + + generic_handle_irq(virq); + +update_status: + /* Update status in case a new IRQ appears */ + raw_spin_lock_irqsave(&info->irq_lock, flags); + status = readl_relaxed(info->base + + IRQ_STATUS + 4 * i); + /* Manage only the interrupt that was enabled */ + status &= readl_relaxed(info->base + IRQ_EN + 4 * i); + raw_spin_unlock_irqrestore(&info->irq_lock, flags); + } + } + chained_irq_exit(chip, desc); +} + +static unsigned int armada_37xx_irq_startup(struct irq_data *d) +{ + /* + * The mask field is a "precomputed bitmask for accessing the + * chip registers" which was introduced for the generic + * irqchip framework. As we don't use this framework, we can + * reuse this field for our own usage. + */ + d->mask = BIT(d->hwirq % GPIO_PER_REG); + + armada_37xx_irq_unmask(d); + + return 0; +} + +static void armada_37xx_irq_print_chip(struct irq_data *d, struct seq_file *p) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct armada_37xx_pinctrl *info = gpiochip_get_data(chip); + + seq_puts(p, info->data->name); +} + +static const struct irq_chip armada_37xx_irqchip = { + .irq_ack = armada_37xx_irq_ack, + .irq_mask = armada_37xx_irq_mask, + .irq_unmask = armada_37xx_irq_unmask, + .irq_set_wake = armada_37xx_irq_set_wake, + .irq_set_type = armada_37xx_irq_set_type, + .irq_startup = armada_37xx_irq_startup, + .irq_print_chip = armada_37xx_irq_print_chip, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int armada_37xx_irqchip_register(struct platform_device *pdev, + struct armada_37xx_pinctrl *info) +{ + struct gpio_chip *gc = &info->gpio_chip; + struct gpio_irq_chip *girq = &gc->irq; + struct device_node *np = to_of_node(gc->fwnode); + struct device *dev = &pdev->dev; + unsigned int i, nr_irq_parent; + + raw_spin_lock_init(&info->irq_lock); + + nr_irq_parent = of_irq_count(np); + if (!nr_irq_parent) { + dev_err(dev, "invalid or no IRQ\n"); + return 0; + } + + info->base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(info->base)) + return PTR_ERR(info->base); + + gpio_irq_chip_set_chip(girq, &armada_37xx_irqchip); + girq->parent_handler = armada_37xx_irq_handler; + /* + * Many interrupts are connected to the parent interrupt + * controller. But we do not take advantage of this and use + * the chained irq with all of them. + */ + girq->num_parents = nr_irq_parent; + girq->parents = devm_kcalloc(dev, nr_irq_parent, sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + for (i = 0; i < nr_irq_parent; i++) { + int irq = irq_of_parse_and_map(np, i); + + if (!irq) + continue; + girq->parents[i] = irq; + } + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_edge_irq; + + return 0; +} + +static int armada_37xx_gpiochip_register(struct platform_device *pdev, + struct armada_37xx_pinctrl *info) +{ + struct device *dev = &pdev->dev; + struct fwnode_handle *fwnode; + struct gpio_chip *gc; + int ret; + + fwnode = gpiochip_node_get_first(dev); + if (!fwnode) + return -ENODEV; + + info->gpio_chip = armada_37xx_gpiolib_chip; + + gc = &info->gpio_chip; + gc->ngpio = info->data->nr_pins; + gc->parent = dev; + gc->base = -1; + gc->fwnode = fwnode; + gc->label = info->data->name; + + ret = armada_37xx_irqchip_register(pdev, info); + if (ret) + return ret; + + return devm_gpiochip_add_data(dev, gc, info); +} + +/** + * armada_37xx_add_function() - Add a new function to the list + * @funcs: array of function to add the new one + * @funcsize: size of the remaining space for the function + * @name: name of the function to add + * + * If it is a new function then create it by adding its name else + * increment the number of group associated to this function. + */ +static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs, + int *funcsize, const char *name) +{ + if (*funcsize <= 0) + return -EOVERFLOW; + + while (funcs->ngroups) { + /* function already there */ + if (strcmp(funcs->name, name) == 0) { + funcs->ngroups++; + + return -EEXIST; + } + funcs++; + } + + /* append new unique function */ + funcs->name = name; + funcs->ngroups = 1; + (*funcsize)--; + + return 0; +} + +/** + * armada_37xx_fill_group() - complete the group array + * @info: info driver instance + * + * Based on the data available from the armada_37xx_pin_group array + * completes the last member of the struct for each function: the list + * of the groups associated to this function. + * + */ +static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info) +{ + int n, num = 0, funcsize = info->data->nr_pins; + struct device *dev = info->dev; + + for (n = 0; n < info->ngroups; n++) { + struct armada_37xx_pin_group *grp = &info->groups[n]; + int i, j, f; + + grp->pins = devm_kcalloc(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 (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++) { + int ret; + /* check for unique functions and count groups */ + ret = armada_37xx_add_function(info->funcs, &funcsize, + grp->funcs[f]); + if (ret == -EOVERFLOW) + dev_err(dev, "More functions than pins(%d)\n", + info->data->nr_pins); + if (ret < 0) + continue; + num++; + } + } + + info->nfuncs = num; + + return 0; +} + +/** + * armada_37xx_fill_func() - complete the funcs array + * @info: info driver instance + * + * Based on the data available from the armada_37xx_pin_group array + * completes the last two member of the struct for each group: + * - the list of the pins included in the group + * - the list of pinmux functions that can be selected for this group + * + */ +static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info) +{ + struct armada_37xx_pmx_func *funcs = info->funcs; + struct device *dev = info->dev; + int n; + + for (n = 0; n < info->nfuncs; n++) { + const char *name = funcs[n].name; + const char **groups; + int g; + + funcs[n].groups = devm_kcalloc(dev, funcs[n].ngroups, + sizeof(*(funcs[n].groups)), + GFP_KERNEL); + if (!funcs[n].groups) + return -ENOMEM; + + groups = funcs[n].groups; + + for (g = 0; g < info->ngroups; g++) { + struct armada_37xx_pin_group *gp = &info->groups[g]; + int f; + + f = match_string(gp->funcs, NB_FUNCS, name); + if (f < 0) + continue; + + *groups = gp->name; + groups++; + } + } + return 0; +} + +static int armada_37xx_pinctrl_register(struct platform_device *pdev, + struct armada_37xx_pinctrl *info) +{ + const struct armada_37xx_pin_data *pin_data = info->data; + struct pinctrl_desc *ctrldesc = &info->pctl; + struct pinctrl_pin_desc *pindesc, *pdesc; + struct device *dev = &pdev->dev; + char **pin_names; + int pin, ret; + + info->groups = pin_data->groups; + info->ngroups = pin_data->ngroups; + + ctrldesc->name = "armada_37xx-pinctrl"; + ctrldesc->owner = THIS_MODULE; + ctrldesc->pctlops = &armada_37xx_pctrl_ops; + ctrldesc->pmxops = &armada_37xx_pmx_ops; + ctrldesc->confops = &armada_37xx_pinconf_ops; + + pindesc = devm_kcalloc(dev, pin_data->nr_pins, sizeof(*pindesc), GFP_KERNEL); + if (!pindesc) + return -ENOMEM; + + ctrldesc->pins = pindesc; + ctrldesc->npins = pin_data->nr_pins; + + pin_names = devm_kasprintf_strarray(dev, pin_data->name, pin_data->nr_pins); + if (IS_ERR(pin_names)) + return PTR_ERR(pin_names); + + pdesc = pindesc; + for (pin = 0; pin < pin_data->nr_pins; pin++) { + pdesc->number = pin; + pdesc->name = pin_names[pin]; + pdesc++; + } + + /* + * we allocate functions for number of pins and hope there are + * fewer unique functions than pins available + */ + info->funcs = devm_kcalloc(dev, pin_data->nr_pins, sizeof(*info->funcs), GFP_KERNEL); + if (!info->funcs) + return -ENOMEM; + + ret = armada_37xx_fill_group(info); + if (ret) + return ret; + + ret = armada_37xx_fill_func(info); + if (ret) + return ret; + + info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info); + if (IS_ERR(info->pctl_dev)) + return dev_err_probe(dev, PTR_ERR(info->pctl_dev), "could not register pinctrl driver\n"); + + return 0; +} + +static int armada_3700_pinctrl_suspend(struct device *dev) +{ + struct armada_37xx_pinctrl *info = dev_get_drvdata(dev); + + /* Save GPIO state */ + regmap_read(info->regmap, OUTPUT_EN, &info->pm.out_en_l); + regmap_read(info->regmap, OUTPUT_EN + sizeof(u32), &info->pm.out_en_h); + regmap_read(info->regmap, OUTPUT_VAL, &info->pm.out_val_l); + regmap_read(info->regmap, OUTPUT_VAL + sizeof(u32), + &info->pm.out_val_h); + + info->pm.irq_en_l = readl(info->base + IRQ_EN); + info->pm.irq_en_h = readl(info->base + IRQ_EN + sizeof(u32)); + info->pm.irq_pol_l = readl(info->base + IRQ_POL); + info->pm.irq_pol_h = readl(info->base + IRQ_POL + sizeof(u32)); + + /* Save pinctrl state */ + regmap_read(info->regmap, SELECTION, &info->pm.selection); + + return 0; +} + +static int armada_3700_pinctrl_resume(struct device *dev) +{ + struct armada_37xx_pinctrl *info = dev_get_drvdata(dev); + struct gpio_chip *gc; + struct irq_domain *d; + int i; + + /* Restore GPIO state */ + regmap_write(info->regmap, OUTPUT_EN, info->pm.out_en_l); + regmap_write(info->regmap, OUTPUT_EN + sizeof(u32), + info->pm.out_en_h); + regmap_write(info->regmap, OUTPUT_VAL, info->pm.out_val_l); + regmap_write(info->regmap, OUTPUT_VAL + sizeof(u32), + info->pm.out_val_h); + + /* + * Input levels may change during suspend, which is not monitored at + * that time. GPIOs used for both-edge IRQs may not be synchronized + * anymore with their polarities (rising/falling edge) and must be + * re-configured manually. + */ + gc = &info->gpio_chip; + d = gc->irq.domain; + for (i = 0; i < gc->ngpio; i++) { + u32 irq_bit = BIT(i % GPIO_PER_REG); + u32 mask, *irq_pol, input_reg, virq, type, level; + + if (i < GPIO_PER_REG) { + mask = info->pm.irq_en_l; + irq_pol = &info->pm.irq_pol_l; + input_reg = INPUT_VAL; + } else { + mask = info->pm.irq_en_h; + irq_pol = &info->pm.irq_pol_h; + input_reg = INPUT_VAL + sizeof(u32); + } + + if (!(mask & irq_bit)) + continue; + + virq = irq_find_mapping(d, i); + type = irq_get_trigger_type(virq); + + /* + * Synchronize level and polarity for both-edge irqs: + * - a high input level expects a falling edge, + * - a low input level exepects a rising edge. + */ + if ((type & IRQ_TYPE_SENSE_MASK) == + IRQ_TYPE_EDGE_BOTH) { + regmap_read(info->regmap, input_reg, &level); + if ((*irq_pol ^ level) & irq_bit) + *irq_pol ^= irq_bit; + } + } + + writel(info->pm.irq_en_l, info->base + IRQ_EN); + writel(info->pm.irq_en_h, info->base + IRQ_EN + sizeof(u32)); + writel(info->pm.irq_pol_l, info->base + IRQ_POL); + writel(info->pm.irq_pol_h, info->base + IRQ_POL + sizeof(u32)); + + /* Restore pinctrl state */ + regmap_write(info->regmap, SELECTION, info->pm.selection); + + return 0; +} + +/* + * Since pinctrl is an infrastructure module, its resume should be issued prior + * to other IO drivers. + */ +static DEFINE_NOIRQ_DEV_PM_OPS(armada_3700_pinctrl_pm_ops, + armada_3700_pinctrl_suspend, armada_3700_pinctrl_resume); + +static const struct of_device_id armada_37xx_pinctrl_of_match[] = { + { + .compatible = "marvell,armada3710-sb-pinctrl", + .data = &armada_37xx_pin_sb, + }, + { + .compatible = "marvell,armada3710-nb-pinctrl", + .data = &armada_37xx_pin_nb, + }, + { }, +}; + +static const struct regmap_config armada_37xx_pinctrl_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .use_raw_spinlock = true, +}; + +static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev) +{ + struct armada_37xx_pinctrl *info; + struct device *dev = &pdev->dev; + struct regmap *regmap; + void __iomem *base; + int ret; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(base)) { + dev_err(dev, "failed to ioremap base address: %pe\n", base); + return PTR_ERR(base); + } + + regmap = devm_regmap_init_mmio(dev, base, + &armada_37xx_pinctrl_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "failed to create regmap: %pe\n", regmap); + return PTR_ERR(regmap); + } + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = dev; + info->regmap = regmap; + info->data = of_device_get_match_data(dev); + + ret = armada_37xx_pinctrl_register(pdev, info); + if (ret) + return ret; + + ret = armada_37xx_gpiochip_register(pdev, info); + if (ret) + return ret; + + platform_set_drvdata(pdev, info); + + return 0; +} + +static struct platform_driver armada_37xx_pinctrl_driver = { + .driver = { + .name = "armada-37xx-pinctrl", + .of_match_table = armada_37xx_pinctrl_of_match, + .pm = pm_sleep_ptr(&armada_3700_pinctrl_pm_ops), + }, +}; + +builtin_platform_driver_probe(armada_37xx_pinctrl_driver, + armada_37xx_pinctrl_probe); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c new file mode 100644 index 000000000..162dfc213 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada 380/385 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2013 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> + +#include "pinctrl-mvebu.h" + +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(0, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), + MPP_VAR_FUNCTION(1, "ua0", "rxd", V_88F6810_PLUS)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), + MPP_VAR_FUNCTION(1, "ua0", "txd", V_88F6810_PLUS)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), + MPP_VAR_FUNCTION(1, "i2c0", "sck", V_88F6810_PLUS)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), + MPP_VAR_FUNCTION(1, "i2c0", "sda", V_88F6810_PLUS)), + MPP_MODE(4, + 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(5, + 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(6, + 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(7, + 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(8, + 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(9, + 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(10, + 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(11, + 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(12, + 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(13, + 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(14, + 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(15, + 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(16, + 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(17, + 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(18, + 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(19, + 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(20, + 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(21, + 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(22, + 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(23, + 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(24, + 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(25, + 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(26, + 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(27, + 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(28, + 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(29, + 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(30, + 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(31, + 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(32, + 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(33, + 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(34, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6810_PLUS)), + MPP_MODE(35, + 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(36, + 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(37, + 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(38, + 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(39, + 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(40, + 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(41, + 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(42, + 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(43, + 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(44, + 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(45, + 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(46, + 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(47, + 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(48, + 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(49, + 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(50, + 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(51, + 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(52, + 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(53, + 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(54, + 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(55, + 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(56, + 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(57, + 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(58, + 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(59, + 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 struct mvebu_pinctrl_soc_info armada_38x_pinctrl_info; + +static const struct of_device_id armada_38x_pinctrl_of_match[] = { + { + .compatible = "marvell,mv88f6810-pinctrl", + .data = (void *) V_88F6810, + }, + { + .compatible = "marvell,mv88f6820-pinctrl", + .data = (void *) V_88F6820, + }, + { + .compatible = "marvell,mv88f6828-pinctrl", + .data = (void *) V_88F6828, + }, + { }, +}; + +static const struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = { + MPP_FUNC_CTRL(0, 59, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 28), +}; + +static int armada_38x_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_38x_pinctrl_info; + + soc->variant = (unsigned)device_get_match_data(&pdev->dev) & 0xff; + soc->controls = armada_38x_mpp_controls; + soc->ncontrols = ARRAY_SIZE(armada_38x_mpp_controls); + soc->gpioranges = armada_38x_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(armada_38x_mpp_gpio_ranges); + soc->modes = armada_38x_mpp_modes; + soc->nmodes = armada_38x_mpp_controls[0].npins; + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver armada_38x_pinctrl_driver = { + .driver = { + .name = "armada-38x-pinctrl", + .of_match_table = of_match_ptr(armada_38x_pinctrl_of_match), + }, + .probe = armada_38x_pinctrl_probe, +}; +builtin_platform_driver(armada_38x_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-39x.c b/drivers/pinctrl/mvebu/pinctrl-armada-39x.c new file mode 100644 index 000000000..d9c98faa7 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-39x.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada 39x pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2015 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> + +#include "pinctrl-mvebu.h" + +enum { + V_88F6920 = BIT(0), + V_88F6925 = BIT(1), + V_88F6928 = BIT(2), + V_88F6920_PLUS = (V_88F6920 | V_88F6925 | V_88F6928), + V_88F6925_PLUS = (V_88F6925 | V_88F6928), +}; + +static struct mvebu_mpp_mode armada_39x_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua0", "rxd", V_88F6920_PLUS)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua0", "txd", V_88F6920_PLUS)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "i2c0", "sck", V_88F6920_PLUS)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "i2c0", "sda", V_88F6920_PLUS)), + MPP_MODE(4, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "smi", "mdc", V_88F6920_PLUS)), + MPP_MODE(5, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "smi", "mdio", V_88F6920_PLUS)), + MPP_MODE(6, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "cs3", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "xsmi", "mdio", V_88F6920_PLUS)), + MPP_MODE(7, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad9", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "xsmi", "mdc", V_88F6920_PLUS)), + MPP_MODE(8, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad10", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ptp", "trig", V_88F6920_PLUS)), + MPP_MODE(9, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad11", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ptp", "clk", V_88F6920_PLUS)), + MPP_MODE(10, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad12", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ptp", "evreq", V_88F6920_PLUS)), + MPP_MODE(11, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad13", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "led", "clk", V_88F6920_PLUS)), + MPP_MODE(12, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad14", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "led", "stb", V_88F6920_PLUS)), + MPP_MODE(13, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad15", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "pcie2", "clkreq", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "led", "data", V_88F6920_PLUS)), + MPP_MODE(14, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "dram", "vttctrl", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "we1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua1", "txd", V_88F6920_PLUS)), + MPP_MODE(15, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi0", "mosi", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c1", "sck", V_88F6920_PLUS)), + MPP_MODE(16, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi0", "miso", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "pcie0", "clkreq", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c1", "sda", V_88F6920_PLUS)), + MPP_MODE(17, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi0", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(6, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(7, "smi", "mdio", V_88F6920_PLUS)), + MPP_MODE(18, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi0", "cs0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c2", "sck", V_88F6920_PLUS)), + MPP_MODE(19, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c2", "sda", V_88F6920_PLUS)), + MPP_MODE(20, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "smi", "mdc", V_88F6920_PLUS)), + MPP_MODE(21, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "cmd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "bootcs", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxd0", V_88F6920_PLUS)), + MPP_MODE(22, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "mosi", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad0", V_88F6920_PLUS)), + MPP_MODE(23, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad2", V_88F6920_PLUS)), + MPP_MODE(24, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "miso", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "ua0", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d4", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ready", V_88F6920_PLUS)), + MPP_MODE(25, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "cs0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "ua0", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d5", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "cs0", V_88F6920_PLUS)), + MPP_MODE(26, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "cs2", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "i2c1", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d6", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "cs1", V_88F6920_PLUS)), + MPP_MODE(27, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "spi0", "cs3", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "i2c1", "sda", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d7", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "cs2", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txclkout", V_88F6920_PLUS)), + MPP_MODE(28, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "clk", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad5", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txd0", V_88F6920_PLUS)), + MPP_MODE(29, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ale0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txd1", V_88F6920_PLUS)), + MPP_MODE(30, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "oe", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txd2", V_88F6920_PLUS)), + MPP_MODE(31, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ale1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txd3", V_88F6920_PLUS)), + MPP_MODE(32, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "we0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "txctl", V_88F6920_PLUS)), + MPP_MODE(33, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "dram", "deccerr", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad3", V_88F6920_PLUS)), + MPP_MODE(34, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad1", V_88F6920_PLUS)), + MPP_MODE(35, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "a1", V_88F6920_PLUS)), + MPP_MODE(36, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "a0", V_88F6920_PLUS)), + MPP_MODE(37, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d3", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad8", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxclk", V_88F6920_PLUS)), + MPP_MODE(38, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ref", "clk_out0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad4", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxd1", V_88F6920_PLUS)), + MPP_MODE(39, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "i2c1", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "a2", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxd2", V_88F6920_PLUS)), + MPP_MODE(40, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "i2c1", "sda", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "sd0", "d2", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad6", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxd3", V_88F6920_PLUS)), + MPP_MODE(41, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "cs3", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "burst/last", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "nand", "rb0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(8, "ge", "rxctl", V_88F6920_PLUS)), + MPP_MODE(42, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "ua0", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "ad7", V_88F6920_PLUS)), + MPP_MODE(43, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "pcie0", "clkreq", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "cs2", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "dev", "clkout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "nand", "rb1", V_88F6920_PLUS)), + MPP_MODE(44, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(4, "sata3", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(7, "led", "clk", V_88F6920_PLUS)), + MPP_MODE(45, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ref", "clk_out0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS)), + MPP_MODE(46, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ref", "clk_out1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "led", "stb", V_88F6920_PLUS)), + MPP_MODE(47, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(3, "sata2", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(5, "sata3", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(7, "led", "data", V_88F6920_PLUS)), + MPP_MODE(48, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(2, "dram", "vttctrl", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "tdm", "pclk", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "mclk", V_88F6928), + MPP_VAR_FUNCTION(5, "sd0", "d4", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "pcie0", "clkreq", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua1", "txd", V_88F6920_PLUS)), + MPP_MODE(49, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata2", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(2, "sata3", "prsnt", V_88F6928), + MPP_VAR_FUNCTION(3, "tdm", "fsync", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "lrclk", V_88F6928), + MPP_VAR_FUNCTION(5, "sd0", "d5", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua2", "rxd", V_88F6920_PLUS)), + MPP_MODE(50, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "tdm", "drx", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "extclk", V_88F6928), + MPP_VAR_FUNCTION(5, "sd0", "cmd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua2", "rxd", V_88F6920_PLUS)), + MPP_MODE(51, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "tdm", "dtx", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "sdo", V_88F6928), + MPP_VAR_FUNCTION(5, "dram", "deccerr", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua2", "txd", V_88F6920_PLUS)), + MPP_MODE(52, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "tdm", "int", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "sdi", V_88F6928), + MPP_VAR_FUNCTION(5, "sd0", "d6", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c3", "sck", V_88F6920_PLUS)), + MPP_MODE(53, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(2, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(3, "tdm", "rst", V_88F6928), + MPP_VAR_FUNCTION(4, "audio", "bclk", V_88F6928), + MPP_VAR_FUNCTION(5, "sd0", "d7", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "i2c3", "sda", V_88F6920_PLUS)), + MPP_MODE(54, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "sata0", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(2, "sata1", "prsnt", V_88F6925_PLUS), + MPP_VAR_FUNCTION(3, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sd0", "d3", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua3", "txd", V_88F6920_PLUS)), + MPP_MODE(55, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua1", "cts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "cs1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sd0", "d0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS), + MPP_VAR_FUNCTION(7, "ua3", "rxd", V_88F6920_PLUS)), + MPP_MODE(56, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "ua1", "rts", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "dram", "deccerr", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "mosi", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS)), + MPP_MODE(57, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sd0", "clk", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6920_PLUS)), + MPP_MODE(58, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "i2c1", "sck", V_88F6920_PLUS), + MPP_VAR_FUNCTION(3, "pcie2", "clkreq", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "miso", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sd0", "d1", V_88F6920_PLUS), + MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6920_PLUS)), + MPP_MODE(59, + MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6920_PLUS), + MPP_VAR_FUNCTION(1, "pcie0", "rstout", V_88F6920_PLUS), + MPP_VAR_FUNCTION(2, "i2c1", "sda", V_88F6920_PLUS), + MPP_VAR_FUNCTION(4, "spi1", "cs0", V_88F6920_PLUS), + MPP_VAR_FUNCTION(5, "sd0", "d2", V_88F6920_PLUS)), +}; + +static struct mvebu_pinctrl_soc_info armada_39x_pinctrl_info; + +static const struct of_device_id armada_39x_pinctrl_of_match[] = { + { + .compatible = "marvell,mv88f6920-pinctrl", + .data = (void *) V_88F6920, + }, + { + .compatible = "marvell,mv88f6925-pinctrl", + .data = (void *) V_88F6925, + }, + { + .compatible = "marvell,mv88f6928-pinctrl", + .data = (void *) V_88F6928, + }, + { }, +}; + +static const struct mvebu_mpp_ctrl armada_39x_mpp_controls[] = { + MPP_FUNC_CTRL(0, 59, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range armada_39x_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 28), +}; + +static int armada_39x_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_39x_pinctrl_info; + + soc->variant = (unsigned)device_get_match_data(&pdev->dev) & 0xff; + soc->controls = armada_39x_mpp_controls; + soc->ncontrols = ARRAY_SIZE(armada_39x_mpp_controls); + soc->gpioranges = armada_39x_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(armada_39x_mpp_gpio_ranges); + soc->modes = armada_39x_mpp_modes; + soc->nmodes = armada_39x_mpp_controls[0].npins; + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver armada_39x_pinctrl_driver = { + .driver = { + .name = "armada-39x-pinctrl", + .of_match_table = of_match_ptr(armada_39x_pinctrl_of_match), + }, + .probe = armada_39x_pinctrl_probe, +}; +builtin_platform_driver(armada_39x_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-ap806.c b/drivers/pinctrl/mvebu/pinctrl-armada-ap806.c new file mode 100644 index 000000000..7becf2781 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-ap806.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada ap806 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2017 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * Hanna Hawa <hannah@marvell.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-mvebu.h" + +static struct mvebu_mpp_mode armada_ap806_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "clk"), + MPP_FUNCTION(3, "spi0", "clk")), + MPP_MODE(1, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "cmd"), + MPP_FUNCTION(3, "spi0", "miso")), + MPP_MODE(2, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d0"), + MPP_FUNCTION(3, "spi0", "mosi")), + MPP_MODE(3, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d1"), + MPP_FUNCTION(3, "spi0", "cs0n")), + MPP_MODE(4, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d2"), + MPP_FUNCTION(3, "i2c0", "sda")), + MPP_MODE(5, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d3"), + MPP_FUNCTION(3, "i2c0", "sdk")), + MPP_MODE(6, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "ds")), + MPP_MODE(7, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d4"), + MPP_FUNCTION(3, "uart1", "rxd")), + MPP_MODE(8, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d5"), + MPP_FUNCTION(3, "uart1", "txd")), + MPP_MODE(9, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d6"), + MPP_FUNCTION(3, "spi0", "cs1n")), + MPP_MODE(10, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "d7")), + MPP_MODE(11, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(3, "uart0", "txd")), + MPP_MODE(12, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "pw_off"), + MPP_FUNCTION(2, "sdio", "hw_rst")), + MPP_MODE(13, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(14, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(15, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(16, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(17, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(18, + MPP_FUNCTION(0, "gpio", NULL)), + MPP_MODE(19, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(3, "uart0", "rxd"), + MPP_FUNCTION(4, "sdio", "pw_off")), +}; + +static struct mvebu_pinctrl_soc_info armada_ap806_pinctrl_info; + +static const struct of_device_id armada_ap806_pinctrl_of_match[] = { + { + .compatible = "marvell,ap806-pinctrl", + }, + { }, +}; + +static const struct mvebu_mpp_ctrl armada_ap806_mpp_controls[] = { + MPP_FUNC_CTRL(0, 19, NULL, mvebu_regmap_mpp_ctrl), +}; + +static struct pinctrl_gpio_range armada_ap806_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 20), +}; + +static int armada_ap806_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_ap806_pinctrl_info; + + if (!pdev->dev.parent) + return -ENODEV; + + soc->variant = 0; /* no variants for Armada AP806 */ + soc->controls = armada_ap806_mpp_controls; + soc->ncontrols = ARRAY_SIZE(armada_ap806_mpp_controls); + soc->gpioranges = armada_ap806_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(armada_ap806_mpp_gpio_ranges); + soc->modes = armada_ap806_mpp_modes; + soc->nmodes = armada_ap806_mpp_controls[0].npins; + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_regmap_probe(pdev, pdev->dev.parent, 0); +} + +static struct platform_driver armada_ap806_pinctrl_driver = { + .driver = { + .name = "armada-ap806-pinctrl", + .of_match_table = of_match_ptr(armada_ap806_pinctrl_of_match), + }, + .probe = armada_ap806_pinctrl_probe, +}; + +builtin_platform_driver(armada_ap806_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-cp110.c b/drivers/pinctrl/mvebu/pinctrl-armada-cp110.c new file mode 100644 index 000000000..9a250c491 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-cp110.c @@ -0,0 +1,691 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada CP110 pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2017 Marvell + * + * Hanna Hawa <hannah@marvell.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> +#include <linux/property.h> + +#include "pinctrl-mvebu.h" + +/* + * Even if the pin controller is the same the MMP available depend on the SoC + * integration. + * - In Armada7K (single CP) almost all the MPPs are available (except the + * MMP 39 to 43) + * - In Armada8K (dual CP) the MPPs are split into 2 parts, MPPs 0-31 from + * CPS, and MPPs 32-62 from CPM, the below flags (V_ARMADA_8K_CPM, + * V_ARMADA_8K_CPS) set which MPP is available to the CPx. + * The x_PLUS enum mean that the MPP available for CPx and for Armada70x0 + */ +enum { + V_ARMADA_7K = BIT(0), + V_ARMADA_8K_CPM = BIT(1), + V_ARMADA_8K_CPS = BIT(2), + V_CP115_STANDALONE = BIT(3), + V_ARMADA_7K_8K_CPM = (V_ARMADA_7K | V_ARMADA_8K_CPM), + V_ARMADA_7K_8K_CPS = (V_ARMADA_7K | V_ARMADA_8K_CPS), +}; + +static struct mvebu_mpp_mode armada_cp110_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ale1"), + MPP_FUNCTION(2, "au", "i2smclk"), + MPP_FUNCTION(3, "ge0", "rxd3"), + MPP_FUNCTION(4, "tdm", "pclk"), + MPP_FUNCTION(6, "ptp", "pulse"), + MPP_FUNCTION(7, "mss_i2c", "sda"), + MPP_FUNCTION(8, "uart0", "rxd"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "ge", "mdio")), + MPP_MODE(1, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ale0"), + MPP_FUNCTION(2, "au", "i2sdo_spdifo"), + MPP_FUNCTION(3, "ge0", "rxd2"), + MPP_FUNCTION(4, "tdm", "drx"), + MPP_FUNCTION(6, "ptp", "clk"), + MPP_FUNCTION(7, "mss_i2c", "sck"), + MPP_FUNCTION(8, "uart0", "txd"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "ge", "mdc")), + MPP_MODE(2, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad15"), + MPP_FUNCTION(2, "au", "i2sextclk"), + MPP_FUNCTION(3, "ge0", "rxd1"), + MPP_FUNCTION(4, "tdm", "dtx"), + MPP_FUNCTION(5, "mss_uart", "rxd"), + MPP_FUNCTION(6, "ptp", "pclk_out"), + MPP_FUNCTION(7, "i2c1", "sck"), + MPP_FUNCTION(8, "uart1", "rxd"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "xg", "mdc")), + MPP_MODE(3, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad14"), + MPP_FUNCTION(2, "au", "i2slrclk"), + MPP_FUNCTION(3, "ge0", "rxd0"), + MPP_FUNCTION(4, "tdm", "fsync"), + MPP_FUNCTION(5, "mss_uart", "txd"), + MPP_FUNCTION(6, "pcie", "rstoutn"), + MPP_FUNCTION(7, "i2c1", "sda"), + MPP_FUNCTION(8, "uart1", "txd"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "xg", "mdio")), + MPP_MODE(4, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad13"), + MPP_FUNCTION(2, "au", "i2sbclk"), + MPP_FUNCTION(3, "ge0", "rxctl"), + MPP_FUNCTION(4, "tdm", "rstn"), + MPP_FUNCTION(5, "mss_uart", "rxd"), + MPP_FUNCTION(6, "uart1", "cts"), + MPP_FUNCTION(7, "pcie0", "clkreq"), + MPP_FUNCTION(8, "uart3", "rxd"), + MPP_FUNCTION(10, "ge", "mdc")), + MPP_MODE(5, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad12"), + MPP_FUNCTION(2, "au", "i2sdi"), + MPP_FUNCTION(3, "ge0", "rxclk"), + MPP_FUNCTION(4, "tdm", "intn"), + MPP_FUNCTION(5, "mss_uart", "txd"), + MPP_FUNCTION(6, "uart1", "rts"), + MPP_FUNCTION(7, "pcie1", "clkreq"), + MPP_FUNCTION(8, "uart3", "txd"), + MPP_FUNCTION(10, "ge", "mdio")), + MPP_MODE(6, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad11"), + MPP_FUNCTION(3, "ge0", "txd3"), + MPP_FUNCTION(4, "spi0", "csn2"), + MPP_FUNCTION(5, "au", "i2sextclk"), + MPP_FUNCTION(6, "sata1", "present_act"), + MPP_FUNCTION(7, "pcie2", "clkreq"), + MPP_FUNCTION(8, "uart0", "rxd"), + MPP_FUNCTION(9, "ptp", "pulse")), + MPP_MODE(7, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad10"), + MPP_FUNCTION(3, "ge0", "txd2"), + MPP_FUNCTION(4, "spi0", "csn1"), + MPP_FUNCTION(5, "spi1", "csn1"), + MPP_FUNCTION(6, "sata0", "present_act"), + MPP_FUNCTION(7, "led", "data"), + MPP_FUNCTION(8, "uart0", "txd"), + MPP_FUNCTION(9, "ptp", "clk")), + MPP_MODE(8, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad9"), + MPP_FUNCTION(3, "ge0", "txd1"), + MPP_FUNCTION(4, "spi0", "csn0"), + MPP_FUNCTION(5, "spi1", "csn0"), + MPP_FUNCTION(6, "uart0", "cts"), + MPP_FUNCTION(7, "led", "stb"), + MPP_FUNCTION(8, "uart2", "rxd"), + MPP_FUNCTION(9, "ptp", "pclk_out"), + MPP_FUNCTION(10, "synce1", "clk")), + MPP_MODE(9, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad8"), + MPP_FUNCTION(3, "ge0", "txd0"), + MPP_FUNCTION(4, "spi0", "mosi"), + MPP_FUNCTION(5, "spi1", "mosi"), + MPP_FUNCTION(7, "pcie", "rstoutn"), + MPP_FUNCTION(10, "synce2", "clk")), + MPP_MODE(10, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "readyn"), + MPP_FUNCTION(3, "ge0", "txctl"), + MPP_FUNCTION(4, "spi0", "miso"), + MPP_FUNCTION(5, "spi1", "miso"), + MPP_FUNCTION(6, "uart0", "cts"), + MPP_FUNCTION(7, "sata1", "present_act")), + MPP_MODE(11, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "wen1"), + MPP_FUNCTION(3, "ge0", "txclkout"), + MPP_FUNCTION(4, "spi0", "clk"), + MPP_FUNCTION(5, "spi1", "clk"), + MPP_FUNCTION(6, "uart0", "rts"), + MPP_FUNCTION(7, "led", "clk"), + MPP_FUNCTION(8, "uart2", "txd"), + MPP_FUNCTION(9, "sata0", "present_act")), + MPP_MODE(12, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "clk_out"), + MPP_FUNCTION(2, "nf", "rbn1"), + MPP_FUNCTION(3, "spi1", "csn1"), + MPP_FUNCTION(4, "ge0", "rxclk")), + MPP_MODE(13, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "burstn"), + MPP_FUNCTION(2, "nf", "rbn0"), + MPP_FUNCTION(3, "spi1", "miso"), + MPP_FUNCTION(4, "ge0", "rxctl"), + MPP_FUNCTION(8, "mss_spi", "miso")), + MPP_MODE(14, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "bootcsn"), + MPP_FUNCTION(2, "dev", "csn0"), + MPP_FUNCTION(3, "spi1", "csn0"), + MPP_FUNCTION(4, "spi0", "csn3"), + MPP_FUNCTION(5, "au", "i2sextclk"), + MPP_FUNCTION(6, "spi0", "miso"), + MPP_FUNCTION(7, "sata0", "present_act"), + MPP_FUNCTION(8, "mss_spi", "csn")), + MPP_MODE(15, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad7"), + MPP_FUNCTION(3, "spi1", "mosi"), + MPP_FUNCTION(6, "spi0", "mosi"), + MPP_FUNCTION(8, "mss_spi", "mosi"), + MPP_FUNCTION(11, "ptp", "pulse_cp2cp")), + MPP_MODE(16, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad6"), + MPP_FUNCTION(3, "spi1", "clk"), + MPP_FUNCTION(8, "mss_spi", "clk")), + MPP_MODE(17, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad5"), + MPP_FUNCTION(4, "ge0", "txd3")), + MPP_MODE(18, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad4"), + MPP_FUNCTION(4, "ge0", "txd2"), + MPP_FUNCTION(11, "ptp", "clk_cp2cp")), + MPP_MODE(19, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad3"), + MPP_FUNCTION(4, "ge0", "txd1"), + MPP_FUNCTION(11, "wakeup", "out_cp2cp")), + MPP_MODE(20, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad2"), + MPP_FUNCTION(4, "ge0", "txd0")), + MPP_MODE(21, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad1"), + MPP_FUNCTION(4, "ge0", "txctl"), + MPP_FUNCTION(11, "sei", "in_cp2cp")), + MPP_MODE(22, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "ad0"), + MPP_FUNCTION(4, "ge0", "txclkout"), + MPP_FUNCTION(11, "wakeup", "in_cp2cp")), + MPP_MODE(23, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "a1"), + MPP_FUNCTION(5, "au", "i2smclk"), + MPP_FUNCTION(11, "link", "rd_in_cp2cp")), + MPP_MODE(24, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "a0"), + MPP_FUNCTION(5, "au", "i2slrclk")), + MPP_MODE(25, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "oen"), + MPP_FUNCTION(5, "au", "i2sdo_spdifo")), + MPP_MODE(26, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "wen0"), + MPP_FUNCTION(5, "au", "i2sbclk")), + MPP_MODE(27, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "csn0"), + MPP_FUNCTION(2, "spi1", "miso"), + MPP_FUNCTION(3, "mss_gpio4", NULL), + MPP_FUNCTION(4, "ge0", "rxd3"), + MPP_FUNCTION(5, "spi0", "csn4"), + MPP_FUNCTION(8, "ge", "mdio"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "uart0", "rts"), + MPP_FUNCTION(11, "rei", "in_cp2cp")), + MPP_MODE(28, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "csn1"), + MPP_FUNCTION(2, "spi1", "csn0"), + MPP_FUNCTION(3, "mss_gpio5", NULL), + MPP_FUNCTION(4, "ge0", "rxd2"), + MPP_FUNCTION(5, "spi0", "csn5"), + MPP_FUNCTION(6, "pcie2", "clkreq"), + MPP_FUNCTION(7, "ptp", "pulse"), + MPP_FUNCTION(8, "ge", "mdc"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "uart0", "cts"), + MPP_FUNCTION(11, "led", "data")), + MPP_MODE(29, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "csn2"), + MPP_FUNCTION(2, "spi1", "mosi"), + MPP_FUNCTION(3, "mss_gpio6", NULL), + MPP_FUNCTION(4, "ge0", "rxd1"), + MPP_FUNCTION(5, "spi0", "csn6"), + MPP_FUNCTION(6, "pcie1", "clkreq"), + MPP_FUNCTION(7, "ptp", "clk"), + MPP_FUNCTION(8, "mss_i2c", "sda"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "uart0", "rxd"), + MPP_FUNCTION(11, "led", "stb")), + MPP_MODE(30, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "csn3"), + MPP_FUNCTION(2, "spi1", "clk"), + MPP_FUNCTION(3, "mss_gpio7", NULL), + MPP_FUNCTION(4, "ge0", "rxd0"), + MPP_FUNCTION(5, "spi0", "csn7"), + MPP_FUNCTION(6, "pcie0", "clkreq"), + MPP_FUNCTION(7, "ptp", "pclk_out"), + MPP_FUNCTION(8, "mss_i2c", "sck"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "uart0", "txd"), + MPP_FUNCTION(11, "led", "clk")), + MPP_MODE(31, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "dev", "a2"), + MPP_FUNCTION(3, "mss_gpio4", NULL), + MPP_FUNCTION(6, "pcie", "rstoutn"), + MPP_FUNCTION(8, "ge", "mdc")), + MPP_MODE(32, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mii", "col"), + MPP_FUNCTION(2, "mii", "txerr"), + MPP_FUNCTION(3, "mss_spi", "miso"), + MPP_FUNCTION(4, "tdm", "drx"), + MPP_FUNCTION(5, "au", "i2sextclk"), + MPP_FUNCTION(6, "au", "i2sdi"), + MPP_FUNCTION(7, "ge", "mdio"), + MPP_FUNCTION(8, "sdio", "v18_en"), + MPP_FUNCTION(9, "pcie1", "clkreq"), + MPP_FUNCTION(10, "mss_gpio0", NULL)), + MPP_MODE(33, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mii", "txclk"), + MPP_FUNCTION(2, "sdio", "pwr10"), + MPP_FUNCTION(3, "mss_spi", "csn"), + MPP_FUNCTION(4, "tdm", "fsync"), + MPP_FUNCTION(5, "au", "i2smclk"), + MPP_FUNCTION(6, "sdio", "bus_pwr"), + MPP_FUNCTION(8, "xg", "mdio"), + MPP_FUNCTION(9, "pcie2", "clkreq"), + MPP_FUNCTION(10, "mss_gpio1", NULL)), + MPP_MODE(34, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mii", "rxerr"), + MPP_FUNCTION(2, "sdio", "pwr11"), + MPP_FUNCTION(3, "mss_spi", "mosi"), + MPP_FUNCTION(4, "tdm", "dtx"), + MPP_FUNCTION(5, "au", "i2slrclk"), + MPP_FUNCTION(6, "sdio", "wr_protect"), + MPP_FUNCTION(7, "ge", "mdc"), + MPP_FUNCTION(9, "pcie0", "clkreq"), + MPP_FUNCTION(10, "mss_gpio2", NULL)), + MPP_MODE(35, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sata1", "present_act"), + MPP_FUNCTION(2, "i2c1", "sda"), + MPP_FUNCTION(3, "mss_spi", "clk"), + MPP_FUNCTION(4, "tdm", "pclk"), + MPP_FUNCTION(5, "au", "i2sdo_spdifo"), + MPP_FUNCTION(6, "sdio", "card_detect"), + MPP_FUNCTION(7, "xg", "mdio"), + MPP_FUNCTION(8, "ge", "mdio"), + MPP_FUNCTION(9, "pcie", "rstoutn"), + MPP_FUNCTION(10, "mss_gpio3", NULL)), + MPP_MODE(36, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "synce2", "clk"), + MPP_FUNCTION(2, "i2c1", "sck"), + MPP_FUNCTION(3, "ptp", "clk"), + MPP_FUNCTION(4, "synce1", "clk"), + MPP_FUNCTION(5, "au", "i2sbclk"), + MPP_FUNCTION(6, "sata0", "present_act"), + MPP_FUNCTION(7, "xg", "mdc"), + MPP_FUNCTION(8, "ge", "mdc"), + MPP_FUNCTION(9, "pcie2", "clkreq"), + MPP_FUNCTION(10, "mss_gpio5", NULL)), + MPP_MODE(37, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "uart2", "rxd"), + MPP_FUNCTION(2, "i2c0", "sck"), + MPP_FUNCTION(3, "ptp", "pclk_out"), + MPP_FUNCTION(4, "tdm", "intn"), + MPP_FUNCTION(5, "mss_i2c", "sck"), + MPP_FUNCTION(6, "sata1", "present_act"), + MPP_FUNCTION(7, "ge", "mdc"), + MPP_FUNCTION(8, "xg", "mdc"), + MPP_FUNCTION(9, "pcie1", "clkreq"), + MPP_FUNCTION(10, "mss_gpio6", NULL), + MPP_FUNCTION(11, "link", "rd_out_cp2cp")), + MPP_MODE(38, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "uart2", "txd"), + MPP_FUNCTION(2, "i2c0", "sda"), + MPP_FUNCTION(3, "ptp", "pulse"), + MPP_FUNCTION(4, "tdm", "rstn"), + MPP_FUNCTION(5, "mss_i2c", "sda"), + MPP_FUNCTION(6, "sata0", "present_act"), + MPP_FUNCTION(7, "ge", "mdio"), + MPP_FUNCTION(8, "xg", "mdio"), + MPP_FUNCTION(9, "au", "i2sextclk"), + MPP_FUNCTION(10, "mss_gpio7", NULL), + MPP_FUNCTION(11, "ptp", "pulse_cp2cp")), + MPP_MODE(39, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "wr_protect"), + MPP_FUNCTION(4, "au", "i2sbclk"), + MPP_FUNCTION(5, "ptp", "clk"), + MPP_FUNCTION(6, "spi0", "csn1"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "mss_gpio0", NULL)), + MPP_MODE(40, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "pwr11"), + MPP_FUNCTION(2, "synce1", "clk"), + MPP_FUNCTION(3, "mss_i2c", "sda"), + MPP_FUNCTION(4, "au", "i2sdo_spdifo"), + MPP_FUNCTION(5, "ptp", "pclk_out"), + MPP_FUNCTION(6, "spi0", "clk"), + MPP_FUNCTION(7, "uart1", "txd"), + MPP_FUNCTION(8, "ge", "mdio"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "mss_gpio1", NULL)), + MPP_MODE(41, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "pwr10"), + MPP_FUNCTION(2, "sdio", "bus_pwr"), + MPP_FUNCTION(3, "mss_i2c", "sck"), + MPP_FUNCTION(4, "au", "i2slrclk"), + MPP_FUNCTION(5, "ptp", "pulse"), + MPP_FUNCTION(6, "spi0", "mosi"), + MPP_FUNCTION(7, "uart1", "rxd"), + MPP_FUNCTION(8, "ge", "mdc"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "mss_gpio2", NULL), + MPP_FUNCTION(11, "rei", "out_cp2cp")), + MPP_MODE(42, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "v18_en"), + MPP_FUNCTION(2, "sdio", "wr_protect"), + MPP_FUNCTION(3, "synce2", "clk"), + MPP_FUNCTION(4, "au", "i2smclk"), + MPP_FUNCTION(5, "mss_uart", "txd"), + MPP_FUNCTION(6, "spi0", "miso"), + MPP_FUNCTION(7, "uart1", "cts"), + MPP_FUNCTION(8, "xg", "mdc"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "mss_gpio4", NULL)), + MPP_MODE(43, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "sdio", "card_detect"), + MPP_FUNCTION(3, "synce1", "clk"), + MPP_FUNCTION(4, "au", "i2sextclk"), + MPP_FUNCTION(5, "mss_uart", "rxd"), + MPP_FUNCTION(6, "spi0", "csn0"), + MPP_FUNCTION(7, "uart1", "rts"), + MPP_FUNCTION(8, "xg", "mdio"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "mss_gpio5", NULL), + MPP_FUNCTION(11, "wakeup", "out_cp2cp")), + MPP_MODE(44, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txd2"), + MPP_FUNCTION(7, "uart0", "rts"), + MPP_FUNCTION(11, "ptp", "clk_cp2cp")), + MPP_MODE(45, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txd3"), + MPP_FUNCTION(7, "uart0", "txd"), + MPP_FUNCTION(9, "pcie", "rstoutn")), + MPP_MODE(46, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txd1"), + MPP_FUNCTION(7, "uart1", "rts")), + MPP_MODE(47, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txd0"), + MPP_FUNCTION(5, "spi1", "clk"), + MPP_FUNCTION(7, "uart1", "txd"), + MPP_FUNCTION(8, "ge", "mdc")), + MPP_MODE(48, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txctl_txen"), + MPP_FUNCTION(5, "spi1", "mosi"), + MPP_FUNCTION(8, "xg", "mdc"), + MPP_FUNCTION(11, "wakeup", "in_cp2cp")), + MPP_MODE(49, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "txclkout"), + MPP_FUNCTION(2, "mii", "crs"), + MPP_FUNCTION(5, "spi1", "miso"), + MPP_FUNCTION(7, "uart1", "rxd"), + MPP_FUNCTION(8, "ge", "mdio"), + MPP_FUNCTION(9, "pcie0", "clkreq"), + MPP_FUNCTION(10, "sdio", "v18_en"), + MPP_FUNCTION(11, "sei", "out_cp2cp")), + MPP_MODE(50, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxclk"), + MPP_FUNCTION(2, "mss_i2c", "sda"), + MPP_FUNCTION(5, "spi1", "csn0"), + MPP_FUNCTION(6, "uart2", "txd"), + MPP_FUNCTION(7, "uart0", "rxd"), + MPP_FUNCTION(8, "xg", "mdio"), + MPP_FUNCTION(10, "sdio", "pwr11")), + MPP_MODE(51, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxd0"), + MPP_FUNCTION(2, "mss_i2c", "sck"), + MPP_FUNCTION(5, "spi1", "csn1"), + MPP_FUNCTION(6, "uart2", "rxd"), + MPP_FUNCTION(7, "uart0", "cts"), + MPP_FUNCTION(10, "sdio", "pwr10")), + MPP_MODE(52, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxd1"), + MPP_FUNCTION(2, "synce1", "clk"), + MPP_FUNCTION(4, "synce2", "clk"), + MPP_FUNCTION(5, "spi1", "csn2"), + MPP_FUNCTION(7, "uart1", "cts"), + MPP_FUNCTION(8, "led", "clk"), + MPP_FUNCTION(9, "pcie", "rstoutn"), + MPP_FUNCTION(10, "pcie0", "clkreq")), + MPP_MODE(53, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxd2"), + MPP_FUNCTION(3, "ptp", "clk"), + MPP_FUNCTION(5, "spi1", "csn3"), + MPP_FUNCTION(7, "uart1", "rxd"), + MPP_FUNCTION(8, "led", "stb"), + MPP_FUNCTION(11, "sdio", "led")), + MPP_MODE(54, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxd3"), + MPP_FUNCTION(2, "synce2", "clk"), + MPP_FUNCTION(3, "ptp", "pclk_out"), + MPP_FUNCTION(4, "synce1", "clk"), + MPP_FUNCTION(8, "led", "data"), + MPP_FUNCTION(10, "sdio", "hw_rst"), + MPP_FUNCTION(11, "sdio_wp", "wr_protect")), + MPP_MODE(55, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "ge1", "rxctl_rxdv"), + MPP_FUNCTION(3, "ptp", "pulse"), + MPP_FUNCTION(10, "sdio", "led"), + MPP_FUNCTION(11, "sdio_cd", "card_detect")), + MPP_MODE(56, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(4, "tdm", "drx"), + MPP_FUNCTION(5, "au", "i2sdo_spdifo"), + MPP_FUNCTION(6, "spi0", "clk"), + MPP_FUNCTION(7, "uart1", "rxd"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(14, "sdio", "clk")), + MPP_MODE(57, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(2, "mss_i2c", "sda"), + MPP_FUNCTION(3, "ptp", "pclk_out"), + MPP_FUNCTION(4, "tdm", "intn"), + MPP_FUNCTION(5, "au", "i2sbclk"), + MPP_FUNCTION(6, "spi0", "mosi"), + MPP_FUNCTION(7, "uart1", "txd"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(14, "sdio", "cmd")), + MPP_MODE(58, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(2, "mss_i2c", "sck"), + MPP_FUNCTION(3, "ptp", "clk"), + MPP_FUNCTION(4, "tdm", "rstn"), + MPP_FUNCTION(5, "au", "i2sdi"), + MPP_FUNCTION(6, "spi0", "miso"), + MPP_FUNCTION(7, "uart1", "cts"), + MPP_FUNCTION(8, "led", "clk"), + MPP_FUNCTION(14, "sdio", "d0")), + MPP_MODE(59, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mss_gpio7", NULL), + MPP_FUNCTION(2, "synce2", "clk"), + MPP_FUNCTION(4, "tdm", "fsync"), + MPP_FUNCTION(5, "au", "i2slrclk"), + MPP_FUNCTION(6, "spi0", "csn0"), + MPP_FUNCTION(7, "uart0", "cts"), + MPP_FUNCTION(8, "led", "stb"), + MPP_FUNCTION(9, "uart1", "txd"), + MPP_FUNCTION(14, "sdio", "d1")), + MPP_MODE(60, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mss_gpio6", NULL), + MPP_FUNCTION(3, "ptp", "pulse"), + MPP_FUNCTION(4, "tdm", "dtx"), + MPP_FUNCTION(5, "au", "i2smclk"), + MPP_FUNCTION(6, "spi0", "csn1"), + MPP_FUNCTION(7, "uart0", "rts"), + MPP_FUNCTION(8, "led", "data"), + MPP_FUNCTION(9, "uart1", "rxd"), + MPP_FUNCTION(14, "sdio", "d2")), + MPP_MODE(61, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mss_gpio5", NULL), + MPP_FUNCTION(3, "ptp", "clk"), + MPP_FUNCTION(4, "tdm", "pclk"), + MPP_FUNCTION(5, "au", "i2sextclk"), + MPP_FUNCTION(6, "spi0", "csn2"), + MPP_FUNCTION(7, "uart0", "txd"), + MPP_FUNCTION(8, "uart2", "txd"), + MPP_FUNCTION(9, "sata1", "present_act"), + MPP_FUNCTION(10, "ge", "mdio"), + MPP_FUNCTION(14, "sdio", "d3")), + MPP_MODE(62, + MPP_FUNCTION(0, "gpio", NULL), + MPP_FUNCTION(1, "mss_gpio4", NULL), + MPP_FUNCTION(2, "synce1", "clk"), + MPP_FUNCTION(3, "ptp", "pclk_out"), + MPP_FUNCTION(5, "sata1", "present_act"), + MPP_FUNCTION(6, "spi0", "csn3"), + MPP_FUNCTION(7, "uart0", "rxd"), + MPP_FUNCTION(8, "uart2", "rxd"), + MPP_FUNCTION(9, "sata0", "present_act"), + MPP_FUNCTION(10, "ge", "mdc"), + MPP_FUNCTION(14, "sdio", "ds")), +}; + +static const struct of_device_id armada_cp110_pinctrl_of_match[] = { + { + .compatible = "marvell,armada-7k-pinctrl", + .data = (void *) V_ARMADA_7K, + }, + { + .compatible = "marvell,armada-8k-cpm-pinctrl", + .data = (void *) V_ARMADA_8K_CPM, + }, + { + .compatible = "marvell,armada-8k-cps-pinctrl", + .data = (void *) V_ARMADA_8K_CPS, + }, + { + .compatible = "marvell,cp115-standalone-pinctrl", + .data = (void *) V_CP115_STANDALONE, + }, + { }, +}; + +static const struct mvebu_mpp_ctrl armada_cp110_mpp_controls[] = { + MPP_FUNC_CTRL(0, 62, NULL, mvebu_regmap_mpp_ctrl), +}; + +static void mvebu_pinctrl_assign_variant(struct mvebu_mpp_mode *m, + u8 variant) +{ + struct mvebu_mpp_ctrl_setting *s; + + for (s = m->settings ; s->name ; s++) + s->variant = variant; +} + +static int armada_cp110_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc; + int i; + + if (!pdev->dev.parent) + return -ENODEV; + + soc = devm_kzalloc(&pdev->dev, + sizeof(struct mvebu_pinctrl_soc_info), GFP_KERNEL); + if (!soc) + return -ENOMEM; + + soc->variant = (unsigned long)device_get_match_data(&pdev->dev) & 0xff; + soc->controls = armada_cp110_mpp_controls; + soc->ncontrols = ARRAY_SIZE(armada_cp110_mpp_controls); + soc->modes = armada_cp110_mpp_modes; + soc->nmodes = ARRAY_SIZE(armada_cp110_mpp_modes); + for (i = 0; i < ARRAY_SIZE(armada_cp110_mpp_modes); i++) { + struct mvebu_mpp_mode *m = &armada_cp110_mpp_modes[i]; + + switch (i) { + case 0 ... 31: + mvebu_pinctrl_assign_variant(m, (V_ARMADA_7K_8K_CPS | + V_CP115_STANDALONE)); + break; + case 32 ... 38: + mvebu_pinctrl_assign_variant(m, (V_ARMADA_7K_8K_CPM | + V_CP115_STANDALONE)); + break; + case 39 ... 43: + mvebu_pinctrl_assign_variant(m, (V_ARMADA_8K_CPM | + V_CP115_STANDALONE)); + break; + case 44 ... 62: + mvebu_pinctrl_assign_variant(m, (V_ARMADA_7K_8K_CPM | + V_CP115_STANDALONE)); + break; + } + } + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_regmap_probe(pdev, pdev->dev.parent, 0); +} + +static struct platform_driver armada_cp110_pinctrl_driver = { + .driver = { + .name = "armada-cp110-pinctrl", + .of_match_table = of_match_ptr(armada_cp110_pinctrl_of_match), + }, + .probe = armada_cp110_pinctrl_probe, +}; + +builtin_platform_driver(armada_cp110_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c new file mode 100644 index 000000000..487825bfd --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Armada XP pinctrl driver based on mvebu pinctrl core + * + * Copyright (C) 2012 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * + * This file supports the three variants of Armada XP SoCs that are + * available: mv78230, mv78260 and mv78460. From a pin muxing + * perspective, the mv78230 has 49 MPP pins. The mv78260 and mv78460 + * both have 67 MPP pins (more GPIOs and address lines for the memory + * bus mainly). + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> +#include <linux/bitops.h> + +#include "pinctrl-mvebu.h" + +static u32 *mpp_saved_regs; + +enum armada_xp_variant { + V_MV78230 = BIT(0), + V_MV78260 = BIT(1), + V_MV78460 = BIT(2), + V_MV78230_PLUS = (V_MV78230 | V_MV78260 | V_MV78460), + V_MV78260_PLUS = (V_MV78260 | V_MV78460), + V_98DX3236 = BIT(3), + V_98DX3336 = BIT(4), + V_98DX4251 = BIT(5), + V_98DX3236_PLUS = (V_98DX3236 | V_98DX3336 | V_98DX4251), +}; + +static struct mvebu_mpp_mode armada_xp_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txclkout", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d0", V_MV78230_PLUS)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d1", V_MV78230_PLUS)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d2", V_MV78230_PLUS)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d3", V_MV78230_PLUS)), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d4", V_MV78230_PLUS)), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txctl", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d5", V_MV78230_PLUS)), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d6", V_MV78230_PLUS)), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d7", V_MV78230_PLUS)), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d8", V_MV78230_PLUS)), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d9", V_MV78230_PLUS)), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxctl", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d10", V_MV78230_PLUS)), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxclk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d11", V_MV78230_PLUS)), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd4", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txclkout", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d12", V_MV78230_PLUS)), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd5", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txd0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi1", "mosi", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d13", V_MV78230_PLUS)), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd6", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txd1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi1", "sck", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d14", V_MV78230_PLUS)), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txd7", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txd2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d15", V_MV78230_PLUS)), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "txclk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txd3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi1", "cs0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d16", V_MV78230_PLUS)), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "col", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "txctl", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi1", "miso", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d17", V_MV78230_PLUS)), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxerr", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxd0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d18", V_MV78230_PLUS)), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "crs", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxd1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "ptp", "evreq", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d19", V_MV78230_PLUS)), + MPP_MODE(20, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd4", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxd2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "ptp", "clk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d20", V_MV78230_PLUS)), + MPP_MODE(21, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd5", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxd3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "dram", "bat", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d21", V_MV78230_PLUS)), + MPP_MODE(22, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd6", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxctl", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "sata0", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d22", V_MV78230_PLUS)), + MPP_MODE(23, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ge0", "rxd7", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "ge1", "rxclk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "sata1", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "d23", V_MV78230_PLUS)), + MPP_MODE(24, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sata1", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "rst", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "hsync", V_MV78230_PLUS)), + MPP_MODE(25, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sata0", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "pclk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "vsync", V_MV78230_PLUS)), + MPP_MODE(26, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "fsync", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "clk", V_MV78230_PLUS)), + MPP_MODE(27, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ptp", "trig", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "dtx", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "e", V_MV78230_PLUS)), + MPP_MODE(28, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ptp", "evreq", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "drx", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "pwm", V_MV78230_PLUS)), + MPP_MODE(29, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "ptp", "clk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "ref-clk", V_MV78230_PLUS)), + MPP_MODE(30, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "clk", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int1", V_MV78230_PLUS)), + MPP_MODE(31, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "cmd", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int2", V_MV78230_PLUS)), + MPP_MODE(32, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "d0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int3", V_MV78230_PLUS)), + MPP_MODE(33, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "d1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int4", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "dram", "bat", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "dram", "vttctrl", V_MV78230_PLUS)), + MPP_MODE(34, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "d2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "sata0", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int5", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "dram", "deccerr", V_MV78230_PLUS)), + MPP_MODE(35, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "sd0", "d3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "sata1", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int6", V_MV78230_PLUS)), + MPP_MODE(36, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "mosi", V_MV78230_PLUS)), + MPP_MODE(37, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "miso", V_MV78230_PLUS)), + MPP_MODE(38, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "sck", V_MV78230_PLUS)), + MPP_MODE(39, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "cs0", V_MV78230_PLUS)), + MPP_MODE(40, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "cs1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart2", "cts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "vga-hsync", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "pcie", "clkreq0", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs1", V_MV78230_PLUS)), + MPP_MODE(41, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "spi0", "cs2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart2", "rts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "sata1", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "lcd", "vga-vsync", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "pcie", "clkreq1", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs2", V_MV78230_PLUS)), + MPP_MODE(42, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart2", "rxd", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "tdm", "int7", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "tdm", "timer", V_MV78230_PLUS)), + MPP_MODE(43, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart2", "txd", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi0", "cs3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "pcie", "rstout", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs3", V_MV78230_PLUS)), + MPP_MODE(44, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart2", "cts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart3", "rxd", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi0", "cs4", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "dram", "bat", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "pcie", "clkreq2", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs4", V_MV78230_PLUS)), + MPP_MODE(45, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart2", "rts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart3", "txd", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi0", "cs5", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "dram", "vttctrl", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs5", V_MV78230_PLUS)), + MPP_MODE(46, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart3", "rts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart1", "rts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi0", "cs6", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs6", V_MV78230_PLUS)), + MPP_MODE(47, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "uart3", "cts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "uart1", "cts", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "spi0", "cs7", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x4, "ref", "clkout", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x5, "pcie", "clkreq3", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x6, "spi1", "cs7", V_MV78230_PLUS)), + MPP_MODE(48, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "clkout", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x2, "dev", "burst/last", V_MV78230_PLUS), + MPP_VAR_FUNCTION(0x3, "nand", "rb", V_MV78230_PLUS)), + MPP_MODE(49, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "we3", V_MV78260_PLUS)), + MPP_MODE(50, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "we2", V_MV78260_PLUS)), + MPP_MODE(51, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad16", V_MV78260_PLUS)), + MPP_MODE(52, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad17", V_MV78260_PLUS)), + MPP_MODE(53, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad18", V_MV78260_PLUS)), + MPP_MODE(54, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad19", V_MV78260_PLUS)), + MPP_MODE(55, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad20", V_MV78260_PLUS)), + MPP_MODE(56, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad21", V_MV78260_PLUS)), + MPP_MODE(57, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad22", V_MV78260_PLUS)), + MPP_MODE(58, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad23", V_MV78260_PLUS)), + MPP_MODE(59, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad24", V_MV78260_PLUS)), + MPP_MODE(60, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad25", V_MV78260_PLUS)), + MPP_MODE(61, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad26", V_MV78260_PLUS)), + MPP_MODE(62, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad27", V_MV78260_PLUS)), + MPP_MODE(63, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad28", V_MV78260_PLUS)), + MPP_MODE(64, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad29", V_MV78260_PLUS)), + MPP_MODE(65, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad30", V_MV78260_PLUS)), + MPP_MODE(66, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_MV78260_PLUS), + MPP_VAR_FUNCTION(0x1, "dev", "ad31", V_MV78260_PLUS)), +}; + +static struct mvebu_mpp_mode mv98dx3236_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "spi0", "mosi", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad8", V_98DX3236_PLUS)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "spi0", "miso", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad9", V_98DX3236_PLUS)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "spi0", "sck", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad10", V_98DX3236_PLUS)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "spi0", "cs0", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad11", V_98DX3236_PLUS)), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "spi0", "cs1", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "smi", "mdc", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "cs0", V_98DX3236_PLUS)), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "pex", "rsto", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "cmd", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "bootcs", V_98DX3236_PLUS)), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "clk", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "a2", V_98DX3236_PLUS)), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "d0", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "ale0", V_98DX3236_PLUS)), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "d1", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "ale1", V_98DX3236_PLUS)), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "d2", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "ready0", V_98DX3236_PLUS)), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "sd0", "d3", V_98DX4251), + MPP_VAR_FUNCTION(0x4, "dev", "ad12", V_98DX3236_PLUS)), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "uart1", "rxd", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "uart0", "cts", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad13", V_98DX3236_PLUS)), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x2, "uart1", "txd", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "uart0", "rts", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad14", V_98DX3236_PLUS)), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "intr", "out", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad15", V_98DX3236_PLUS)), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "i2c0", "sck", V_98DX3236_PLUS)), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "i2c0", "sda", V_98DX3236_PLUS)), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "oe", V_98DX3236_PLUS)), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "clkout", V_98DX3236_PLUS)), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V_98DX3236_PLUS)), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "nand", "rb", V_98DX3236_PLUS)), + MPP_MODE(20, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "we0", V_98DX3236_PLUS)), + MPP_MODE(21, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad0", V_98DX3236_PLUS)), + MPP_MODE(22, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad1", V_98DX3236_PLUS)), + MPP_MODE(23, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad2", V_98DX3236_PLUS)), + MPP_MODE(24, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad3", V_98DX3236_PLUS)), + MPP_MODE(25, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad4", V_98DX3236_PLUS)), + MPP_MODE(26, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad5", V_98DX3236_PLUS)), + MPP_MODE(27, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad6", V_98DX3236_PLUS)), + MPP_MODE(28, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "ad7", V_98DX3236_PLUS)), + MPP_MODE(29, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "a0", V_98DX3236_PLUS)), + MPP_MODE(30, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "a1", V_98DX3236_PLUS)), + MPP_MODE(31, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "slv_smi", "mdc", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "smi", "mdc", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "we1", V_98DX3236_PLUS)), + MPP_MODE(32, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x1, "slv_smi", "mdio", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x3, "smi", "mdio", V_98DX3236_PLUS), + MPP_VAR_FUNCTION(0x4, "dev", "cs1", V_98DX3236_PLUS)), +}; + +static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info; + +static const struct of_device_id armada_xp_pinctrl_of_match[] = { + { + .compatible = "marvell,mv78230-pinctrl", + .data = (void *) V_MV78230, + }, + { + .compatible = "marvell,mv78260-pinctrl", + .data = (void *) V_MV78260, + }, + { + .compatible = "marvell,mv78460-pinctrl", + .data = (void *) V_MV78460, + }, + { + .compatible = "marvell,98dx3236-pinctrl", + .data = (void *) V_98DX3236, + }, + { + .compatible = "marvell,98dx4251-pinctrl", + .data = (void *) V_98DX4251, + }, + { }, +}; + +static const struct mvebu_mpp_ctrl mv78230_mpp_controls[] = { + MPP_FUNC_CTRL(0, 48, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 17), +}; + +static const struct mvebu_mpp_ctrl mv78260_mpp_controls[] = { + MPP_FUNC_CTRL(0, 66, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 32), + MPP_GPIO_RANGE(2, 64, 64, 3), +}; + +static const struct mvebu_mpp_ctrl mv78460_mpp_controls[] = { + MPP_FUNC_CTRL(0, 66, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 32), + MPP_GPIO_RANGE(2, 64, 64, 3), +}; + +static struct mvebu_mpp_ctrl mv98dx3236_mpp_controls[] = { + MPP_FUNC_CTRL(0, 32, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv98dx3236_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), +}; + +static int armada_xp_pinctrl_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct mvebu_pinctrl_soc_info *soc = + platform_get_drvdata(pdev); + int i, nregs; + + nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG); + + for (i = 0; i < nregs; i++) + mpp_saved_regs[i] = readl(soc->control_data[0].base + i * 4); + + return 0; +} + +static int armada_xp_pinctrl_resume(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = + platform_get_drvdata(pdev); + int i, nregs; + + nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG); + + for (i = 0; i < nregs; i++) + writel(mpp_saved_regs[i], soc->control_data[0].base + i * 4); + + return 0; +} + +static int armada_xp_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info; + int nregs; + + soc->variant = (unsigned)device_get_match_data(&pdev->dev) & 0xff; + + switch (soc->variant) { + case V_MV78230: + soc->controls = mv78230_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv78230_mpp_controls); + soc->modes = armada_xp_mpp_modes; + /* We don't necessarily want the full list of the + * armada_xp_mpp_modes, but only the first 'n' ones + * that are available on this SoC */ + soc->nmodes = mv78230_mpp_controls[0].npins; + soc->gpioranges = mv78230_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv78230_mpp_gpio_ranges); + break; + case V_MV78260: + soc->controls = mv78260_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv78260_mpp_controls); + soc->modes = armada_xp_mpp_modes; + /* We don't necessarily want the full list of the + * armada_xp_mpp_modes, but only the first 'n' ones + * that are available on this SoC */ + soc->nmodes = mv78260_mpp_controls[0].npins; + soc->gpioranges = mv78260_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv78260_mpp_gpio_ranges); + break; + case V_MV78460: + soc->controls = mv78460_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv78460_mpp_controls); + soc->modes = armada_xp_mpp_modes; + /* We don't necessarily want the full list of the + * armada_xp_mpp_modes, but only the first 'n' ones + * that are available on this SoC */ + soc->nmodes = mv78460_mpp_controls[0].npins; + soc->gpioranges = mv78460_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv78460_mpp_gpio_ranges); + break; + case V_98DX3236: + case V_98DX3336: + case V_98DX4251: + /* fall-through */ + soc->controls = mv98dx3236_mpp_controls; + soc->ncontrols = ARRAY_SIZE(mv98dx3236_mpp_controls); + soc->modes = mv98dx3236_mpp_modes; + soc->nmodes = mv98dx3236_mpp_controls[0].npins; + soc->gpioranges = mv98dx3236_mpp_gpio_ranges; + soc->ngpioranges = ARRAY_SIZE(mv98dx3236_mpp_gpio_ranges); + break; + } + + nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG); + + mpp_saved_regs = devm_kmalloc_array(&pdev->dev, nregs, sizeof(u32), + GFP_KERNEL); + if (!mpp_saved_regs) + return -ENOMEM; + + pdev->dev.platform_data = soc; + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver armada_xp_pinctrl_driver = { + .driver = { + .name = "armada-xp-pinctrl", + .of_match_table = armada_xp_pinctrl_of_match, + }, + .probe = armada_xp_pinctrl_probe, + .suspend = armada_xp_pinctrl_suspend, + .resume = armada_xp_pinctrl_resume, +}; +builtin_platform_driver(armada_xp_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c new file mode 100644 index 000000000..dce601d99 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -0,0 +1,873 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Dove pinctrl driver based on mvebu pinctrl core + * + * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/mfd/syscon.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> +#include <linux/regmap.h> + +#include "pinctrl-mvebu.h" + +/* Internal registers can be configured at any 1 MiB aligned address */ +#define INT_REGS_MASK ~(SZ_1M - 1) +#define MPP4_REGS_OFFS 0xd0440 +#define PMU_REGS_OFFS 0xd802c +#define GC_REGS_OFFS 0xe802c + +/* MPP Base registers */ +#define PMU_MPP_GENERAL_CTRL 0x10 +#define AU0_AC97_SEL BIT(16) + +/* MPP Control 4 register */ +#define SPI_GPIO_SEL BIT(5) +#define UART1_GPIO_SEL BIT(4) +#define AU1_GPIO_SEL BIT(3) +#define CAM_GPIO_SEL BIT(2) +#define SD1_GPIO_SEL BIT(1) +#define SD0_GPIO_SEL BIT(0) + +/* PMU Signal Select registers */ +#define PMU_SIGNAL_SELECT_0 0x00 +#define PMU_SIGNAL_SELECT_1 0x04 + +/* Global Config regmap registers */ +#define GLOBAL_CONFIG_1 0x00 +#define TWSI_ENABLE_OPTION1 BIT(7) +#define GLOBAL_CONFIG_2 0x04 +#define TWSI_ENABLE_OPTION2 BIT(20) +#define TWSI_ENABLE_OPTION3 BIT(21) +#define TWSI_OPTION3_GPIO BIT(22) +#define SSP_CTRL_STATUS_1 0x08 +#define SSP_ON_AU1 BIT(0) +#define MPP_GENERAL_CONFIG 0x10 +#define AU1_SPDIFO_GPIO_EN BIT(1) +#define NAND_GPIO_EN BIT(0) + +#define CONFIG_PMU BIT(4) + +static void __iomem *mpp4_base; +static void __iomem *pmu_base; +static struct regmap *gconfmap; + +static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, + unsigned pid, unsigned long *config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL); + unsigned long func; + + if ((pmu & BIT(pid)) == 0) + return mvebu_mmio_mpp_ctrl_get(data, pid, config); + + func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off); + *config = (func >> shift) & MVEBU_MPP_MASK; + *config |= CONFIG_PMU; + + return 0; +} + +static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, + unsigned pid, unsigned long config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL); + unsigned long func; + + if ((config & CONFIG_PMU) == 0) { + writel(pmu & ~BIT(pid), data->base + PMU_MPP_GENERAL_CTRL); + return mvebu_mmio_mpp_ctrl_set(data, pid, config); + } + + writel(pmu | BIT(pid), data->base + PMU_MPP_GENERAL_CTRL); + func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off); + func &= ~(MVEBU_MPP_MASK << shift); + func |= (config & MVEBU_MPP_MASK) << shift; + writel(func, pmu_base + PMU_SIGNAL_SELECT_0 + off); + + return 0; +} + +static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config) +{ + unsigned long mpp4 = readl(mpp4_base); + unsigned long mask; + + switch (pid) { + case 24: /* mpp_camera */ + mask = CAM_GPIO_SEL; + break; + case 40: /* mpp_sdio0 */ + mask = SD0_GPIO_SEL; + break; + case 46: /* mpp_sdio1 */ + mask = SD1_GPIO_SEL; + break; + case 58: /* mpp_spi0 */ + mask = SPI_GPIO_SEL; + break; + case 62: /* mpp_uart1 */ + mask = UART1_GPIO_SEL; + break; + default: + return -EINVAL; + } + + *config = ((mpp4 & mask) != 0); + + return 0; +} + +static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config) +{ + unsigned long mpp4 = readl(mpp4_base); + unsigned long mask; + + switch (pid) { + case 24: /* mpp_camera */ + mask = CAM_GPIO_SEL; + break; + case 40: /* mpp_sdio0 */ + mask = SD0_GPIO_SEL; + break; + case 46: /* mpp_sdio1 */ + mask = SD1_GPIO_SEL; + break; + case 58: /* mpp_spi0 */ + mask = SPI_GPIO_SEL; + break; + case 62: /* mpp_uart1 */ + mask = UART1_GPIO_SEL; + break; + default: + return -EINVAL; + } + + mpp4 &= ~mask; + if (config) + mpp4 |= mask; + + writel(mpp4, mpp4_base); + + return 0; +} + +static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config) +{ + unsigned int gmpp; + + regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp); + *config = ((gmpp & NAND_GPIO_EN) != 0); + + return 0; +} + +static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config) +{ + regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG, + NAND_GPIO_EN, + (config) ? NAND_GPIO_EN : 0); + return 0; +} + +static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config) +{ + unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL); + + *config = ((pmu & AU0_AC97_SEL) != 0); + + return 0; +} + +static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config) +{ + unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL); + + pmu &= ~AU0_AC97_SEL; + if (config) + pmu |= AU0_AC97_SEL; + writel(pmu, data->base + PMU_MPP_GENERAL_CTRL); + + return 0; +} + +static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config) +{ + unsigned int mpp4 = readl(mpp4_base); + unsigned int sspc1; + unsigned int gmpp; + unsigned int gcfg2; + + regmap_read(gconfmap, SSP_CTRL_STATUS_1, &sspc1); + regmap_read(gconfmap, MPP_GENERAL_CONFIG, &gmpp); + regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2); + + *config = 0; + if (mpp4 & AU1_GPIO_SEL) + *config |= BIT(3); + if (sspc1 & SSP_ON_AU1) + *config |= BIT(2); + if (gmpp & AU1_SPDIFO_GPIO_EN) + *config |= BIT(1); + if (gcfg2 & TWSI_OPTION3_GPIO) + *config |= BIT(0); + + /* SSP/TWSI only if I2S1 not set*/ + if ((*config & BIT(3)) == 0) + *config &= ~(BIT(2) | BIT(0)); + /* TWSI only if SPDIFO not set*/ + if ((*config & BIT(1)) == 0) + *config &= ~BIT(0); + return 0; +} + +static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config) +{ + unsigned int mpp4 = readl(mpp4_base); + + mpp4 &= ~AU1_GPIO_SEL; + if (config & BIT(3)) + mpp4 |= AU1_GPIO_SEL; + writel(mpp4, mpp4_base); + + regmap_update_bits(gconfmap, SSP_CTRL_STATUS_1, + SSP_ON_AU1, + (config & BIT(2)) ? SSP_ON_AU1 : 0); + regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG, + AU1_SPDIFO_GPIO_EN, + (config & BIT(1)) ? AU1_SPDIFO_GPIO_EN : 0); + regmap_update_bits(gconfmap, GLOBAL_CONFIG_2, + TWSI_OPTION3_GPIO, + (config & BIT(0)) ? TWSI_OPTION3_GPIO : 0); + + return 0; +} + +/* mpp[52:57] gpio pins depend heavily on current config; + * gpio_req does not try to mux in gpio capabilities to not + * break other functions. If you require all mpps as gpio + * enforce gpio setting by pinctrl mapping. + */ +static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl_data *data, + unsigned pid) +{ + unsigned long config; + + dove_audio1_ctrl_get(data, pid, &config); + + switch (config) { + case 0x02: /* i2s1 : gpio[56:57] */ + case 0x0e: /* ssp : gpio[56:57] */ + if (pid >= 56) + return 0; + return -ENOTSUPP; + case 0x08: /* spdifo : gpio[52:55] */ + case 0x0b: /* twsi : gpio[52:55] */ + if (pid <= 55) + return 0; + return -ENOTSUPP; + case 0x0a: /* all gpio */ + return 0; + /* 0x00 : i2s1/spdifo : no gpio */ + /* 0x0c : ssp/spdifo : no gpio */ + /* 0x0f : ssp/twsi : no gpio */ + } + return -ENOTSUPP; +} + +/* mpp[52:57] has gpio pins capable of in and out */ +static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl_data *data, + unsigned pid, bool input) +{ + if (pid < 52 || pid > 57) + return -ENOTSUPP; + return 0; +} + +static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config) +{ + unsigned int gcfg1; + unsigned int gcfg2; + + regmap_read(gconfmap, GLOBAL_CONFIG_1, &gcfg1); + regmap_read(gconfmap, GLOBAL_CONFIG_2, &gcfg2); + + *config = 0; + if (gcfg1 & TWSI_ENABLE_OPTION1) + *config = 1; + else if (gcfg2 & TWSI_ENABLE_OPTION2) + *config = 2; + else if (gcfg2 & TWSI_ENABLE_OPTION3) + *config = 3; + + return 0; +} + +static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config) +{ + unsigned int gcfg1 = 0; + unsigned int gcfg2 = 0; + + switch (config) { + case 1: + gcfg1 = TWSI_ENABLE_OPTION1; + break; + case 2: + gcfg2 = TWSI_ENABLE_OPTION2; + break; + case 3: + gcfg2 = TWSI_ENABLE_OPTION3; + break; + } + + regmap_update_bits(gconfmap, GLOBAL_CONFIG_1, + TWSI_ENABLE_OPTION1, + gcfg1); + regmap_update_bits(gconfmap, GLOBAL_CONFIG_2, + TWSI_ENABLE_OPTION2 | TWSI_ENABLE_OPTION3, + gcfg2); + + return 0; +} + +static const struct mvebu_mpp_ctrl dove_mpp_controls[] = { + MPP_FUNC_CTRL(0, 15, NULL, dove_pmu_mpp_ctrl), + MPP_FUNC_CTRL(16, 23, NULL, mvebu_mmio_mpp_ctrl), + MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl), + MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl), + MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl), + MPP_FUNC_GPIO_CTRL(52, 57, "mpp_audio1", dove_audio1_ctrl), + MPP_FUNC_CTRL(58, 61, "mpp_spi0", dove_mpp4_ctrl), + MPP_FUNC_CTRL(62, 63, "mpp_uart1", dove_mpp4_ctrl), + MPP_FUNC_CTRL(64, 71, "mpp_nand", dove_nand_ctrl), + MPP_FUNC_CTRL(72, 72, "audio0", dove_audio0_ctrl), + MPP_FUNC_CTRL(73, 73, "twsi", dove_twsi_ctrl), +}; + +static struct mvebu_mpp_mode dove_mpp_modes[] = { + MPP_MODE(0, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart2", "rts"), + MPP_FUNCTION(0x03, "sdio0", "cd"), + MPP_FUNCTION(0x0f, "lcd0", "pwm"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(1, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart2", "cts"), + MPP_FUNCTION(0x03, "sdio0", "wp"), + MPP_FUNCTION(0x0f, "lcd1", "pwm"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(2, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "sata", "prsnt"), + MPP_FUNCTION(0x02, "uart2", "txd"), + MPP_FUNCTION(0x03, "sdio0", "buspwr"), + MPP_FUNCTION(0x04, "uart1", "rts"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(3, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "sata", "act"), + MPP_FUNCTION(0x02, "uart2", "rxd"), + MPP_FUNCTION(0x03, "sdio0", "ledctrl"), + MPP_FUNCTION(0x04, "uart1", "cts"), + MPP_FUNCTION(0x0f, "lcd-spi", "cs1"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(4, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "rts"), + MPP_FUNCTION(0x03, "sdio1", "cd"), + MPP_FUNCTION(0x04, "spi1", "miso"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(5, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "cts"), + MPP_FUNCTION(0x03, "sdio1", "wp"), + MPP_FUNCTION(0x04, "spi1", "cs"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(6, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "txd"), + MPP_FUNCTION(0x03, "sdio1", "buspwr"), + MPP_FUNCTION(0x04, "spi1", "mosi"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(7, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "rxd"), + MPP_FUNCTION(0x03, "sdio1", "ledctrl"), + MPP_FUNCTION(0x04, "spi1", "sck"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(8, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "watchdog", "rstout"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(9, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x05, "pex1", "clkreq"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(10, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x05, "ssp", "sclk"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(11, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "sata", "prsnt"), + MPP_FUNCTION(0x02, "sata-1", "act"), + MPP_FUNCTION(0x03, "sdio0", "ledctrl"), + MPP_FUNCTION(0x04, "sdio1", "ledctrl"), + MPP_FUNCTION(0x05, "pex0", "clkreq"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(12, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "sata", "act"), + MPP_FUNCTION(0x02, "uart2", "rts"), + MPP_FUNCTION(0x03, "audio0", "extclk"), + MPP_FUNCTION(0x04, "sdio1", "cd"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(13, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart2", "cts"), + MPP_FUNCTION(0x03, "audio1", "extclk"), + MPP_FUNCTION(0x04, "sdio1", "wp"), + MPP_FUNCTION(0x05, "ssp", "extclk"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(14, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart2", "txd"), + MPP_FUNCTION(0x04, "sdio1", "buspwr"), + MPP_FUNCTION(0x05, "ssp", "rxd"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(15, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart2", "rxd"), + MPP_FUNCTION(0x04, "sdio1", "ledctrl"), + MPP_FUNCTION(0x05, "ssp", "sfrm"), + MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"), + MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL), + MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL), + MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)), + MPP_MODE(16, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "rts"), + MPP_FUNCTION(0x03, "sdio0", "cd"), + MPP_FUNCTION(0x04, "lcd-spi", "cs1"), + MPP_FUNCTION(0x05, "ac97", "sdi1")), + MPP_MODE(17, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "ac97-1", "sysclko"), + MPP_FUNCTION(0x02, "uart3", "cts"), + MPP_FUNCTION(0x03, "sdio0", "wp"), + MPP_FUNCTION(0x04, "twsi", "sda"), + MPP_FUNCTION(0x05, "ac97", "sdi2")), + MPP_MODE(18, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "txd"), + MPP_FUNCTION(0x03, "sdio0", "buspwr"), + MPP_FUNCTION(0x04, "lcd0", "pwm"), + MPP_FUNCTION(0x05, "ac97", "sdi3")), + MPP_MODE(19, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "uart3", "rxd"), + MPP_FUNCTION(0x03, "sdio0", "ledctrl"), + MPP_FUNCTION(0x04, "twsi", "sck")), + MPP_MODE(20, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "ac97", "sysclko"), + MPP_FUNCTION(0x02, "lcd-spi", "miso"), + MPP_FUNCTION(0x03, "sdio1", "cd"), + MPP_FUNCTION(0x05, "sdio0", "cd"), + MPP_FUNCTION(0x06, "spi1", "miso")), + MPP_MODE(21, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "uart1", "rts"), + MPP_FUNCTION(0x02, "lcd-spi", "cs0"), + MPP_FUNCTION(0x03, "sdio1", "wp"), + MPP_FUNCTION(0x04, "ssp", "sfrm"), + MPP_FUNCTION(0x05, "sdio0", "wp"), + MPP_FUNCTION(0x06, "spi1", "cs")), + MPP_MODE(22, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x01, "uart1", "cts"), + MPP_FUNCTION(0x02, "lcd-spi", "mosi"), + MPP_FUNCTION(0x03, "sdio1", "buspwr"), + MPP_FUNCTION(0x04, "ssp", "txd"), + MPP_FUNCTION(0x05, "sdio0", "buspwr"), + MPP_FUNCTION(0x06, "spi1", "mosi")), + MPP_MODE(23, + MPP_FUNCTION(0x00, "gpio", NULL), + MPP_FUNCTION(0x02, "lcd-spi", "sck"), + MPP_FUNCTION(0x03, "sdio1", "ledctrl"), + MPP_FUNCTION(0x04, "ssp", "sclk"), + MPP_FUNCTION(0x05, "sdio0", "ledctrl"), + MPP_FUNCTION(0x06, "spi1", "sck")), + MPP_MODE(24, + MPP_FUNCTION(0x00, "camera", NULL), + MPP_FUNCTION(0x01, "gpio", NULL)), + MPP_MODE(40, + MPP_FUNCTION(0x00, "sdio0", NULL), + MPP_FUNCTION(0x01, "gpio", NULL)), + MPP_MODE(46, + MPP_FUNCTION(0x00, "sdio1", NULL), + MPP_FUNCTION(0x01, "gpio", NULL)), + MPP_MODE(52, + MPP_FUNCTION(0x00, "i2s1/spdifo", NULL), + MPP_FUNCTION(0x02, "i2s1", NULL), + MPP_FUNCTION(0x08, "spdifo", NULL), + MPP_FUNCTION(0x0a, "gpio", NULL), + MPP_FUNCTION(0x0b, "twsi", NULL), + MPP_FUNCTION(0x0c, "ssp/spdifo", NULL), + MPP_FUNCTION(0x0e, "ssp", NULL), + MPP_FUNCTION(0x0f, "ssp/twsi", NULL)), + MPP_MODE(58, + MPP_FUNCTION(0x00, "spi0", NULL), + MPP_FUNCTION(0x01, "gpio", NULL)), + MPP_MODE(62, + MPP_FUNCTION(0x00, "uart1", NULL), + MPP_FUNCTION(0x01, "gpio", NULL)), + MPP_MODE(64, + MPP_FUNCTION(0x00, "nand", NULL), + MPP_FUNCTION(0x01, "gpo", NULL)), + MPP_MODE(72, + MPP_FUNCTION(0x00, "i2s", NULL), + MPP_FUNCTION(0x01, "ac97", NULL)), + MPP_MODE(73, + MPP_FUNCTION(0x00, "twsi-none", NULL), + MPP_FUNCTION(0x01, "twsi-opt1", NULL), + MPP_FUNCTION(0x02, "twsi-opt2", NULL), + MPP_FUNCTION(0x03, "twsi-opt3", NULL)), +}; + +static struct pinctrl_gpio_range dove_mpp_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 32), + MPP_GPIO_RANGE(2, 64, 64, 8), +}; + +static struct mvebu_pinctrl_soc_info dove_pinctrl_info = { + .controls = dove_mpp_controls, + .ncontrols = ARRAY_SIZE(dove_mpp_controls), + .modes = dove_mpp_modes, + .nmodes = ARRAY_SIZE(dove_mpp_modes), + .gpioranges = dove_mpp_gpio_ranges, + .ngpioranges = ARRAY_SIZE(dove_mpp_gpio_ranges), + .variant = 0, +}; + +static struct clk *clk; + +static const struct of_device_id dove_pinctrl_of_match[] = { + { .compatible = "marvell,dove-pinctrl", .data = &dove_pinctrl_info }, + { } +}; + +static const struct regmap_config gc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 5, +}; + +static int dove_pinctrl_probe(struct platform_device *pdev) +{ + struct resource *res, *mpp_res; + struct resource fb_res; + struct mvebu_mpp_ctrl_data *mpp_data; + void __iomem *base; + int i, ret; + + pdev->dev.platform_data = (void *)device_get_match_data(&pdev->dev); + + /* + * General MPP Configuration Register is part of pdma registers. + * grab clk to make sure it is ticking. + */ + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to get pdma clock"); + return PTR_ERR(clk); + } + clk_prepare_enable(clk); + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &mpp_res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err_probe; + } + + mpp_data = devm_kcalloc(&pdev->dev, dove_pinctrl_info.ncontrols, + sizeof(*mpp_data), GFP_KERNEL); + if (!mpp_data) { + ret = -ENOMEM; + goto err_probe; + } + + dove_pinctrl_info.control_data = mpp_data; + for (i = 0; i < ARRAY_SIZE(dove_mpp_controls); i++) + mpp_data[i].base = base; + + /* prepare fallback resource */ + memcpy(&fb_res, mpp_res, sizeof(struct resource)); + fb_res.start = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_warn(&pdev->dev, "falling back to hardcoded MPP4 resource\n"); + adjust_resource(&fb_res, + (mpp_res->start & INT_REGS_MASK) + MPP4_REGS_OFFS, 0x4); + res = &fb_res; + } + + mpp4_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mpp4_base)) { + ret = PTR_ERR(mpp4_base); + goto err_probe; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!res) { + dev_warn(&pdev->dev, "falling back to hardcoded PMU resource\n"); + adjust_resource(&fb_res, + (mpp_res->start & INT_REGS_MASK) + PMU_REGS_OFFS, 0x8); + res = &fb_res; + } + + pmu_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pmu_base)) { + ret = PTR_ERR(pmu_base); + goto err_probe; + } + + gconfmap = syscon_regmap_lookup_by_compatible("marvell,dove-global-config"); + if (IS_ERR(gconfmap)) { + void __iomem *gc_base; + + dev_warn(&pdev->dev, "falling back to hardcoded global registers\n"); + adjust_resource(&fb_res, + (mpp_res->start & INT_REGS_MASK) + GC_REGS_OFFS, 0x14); + gc_base = devm_ioremap_resource(&pdev->dev, &fb_res); + if (IS_ERR(gc_base)) { + ret = PTR_ERR(gc_base); + goto err_probe; + } + + gconfmap = devm_regmap_init_mmio(&pdev->dev, + gc_base, &gc_regmap_config); + if (IS_ERR(gconfmap)) { + ret = PTR_ERR(gconfmap); + goto err_probe; + } + } + + /* Warn on any missing DT resource */ + if (fb_res.start) + dev_warn(&pdev->dev, FW_BUG "Missing pinctrl regs in DTB. Please update your firmware.\n"); + + return mvebu_pinctrl_probe(pdev); +err_probe: + clk_disable_unprepare(clk); + return ret; +} + +static struct platform_driver dove_pinctrl_driver = { + .driver = { + .name = "dove-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = dove_pinctrl_of_match, + }, + .probe = dove_pinctrl_probe, +}; +builtin_platform_driver(dove_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c new file mode 100644 index 000000000..4789d7442 --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Kirkwood pinctrl driver based on mvebu pinctrl core + * + * Author: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> + +#include "pinctrl-mvebu.h" + +#define V(f6180, f6190, f6192, f6281, f6282, dx4122, dx1135) \ + ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) | \ + (f6281 << 3) | (f6282 << 4) | (dx4122 << 5) | \ + (dx1135 << 6)) + +enum kirkwood_variant { + VARIANT_MV88F6180 = V(1, 0, 0, 0, 0, 0, 0), + VARIANT_MV88F6190 = V(0, 1, 0, 0, 0, 0, 0), + VARIANT_MV88F6192 = V(0, 0, 1, 0, 0, 0, 0), + VARIANT_MV88F6281 = V(0, 0, 0, 1, 0, 0, 0), + VARIANT_MV88F6282 = V(0, 0, 0, 0, 1, 0, 0), + VARIANT_MV98DX4122 = V(0, 0, 0, 0, 0, 1, 0), + VARIANT_MV98DX1135 = V(0, 0, 0, 0, 0, 0, 1), +}; + +static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io2", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1))), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io3", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1))), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io4", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1))), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io5", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1))), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io6", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0))), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io7", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "cs", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sda", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "mii-1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "twsi0", "sck", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "evreq", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "sck", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0X3, "uart0", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp", "trig", V(1, 1, 1, 1, 0, 0, 0))), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "spi", "miso", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart0", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "ptp-1", "evreq", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xc, "ptp-2", "trig", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xd, "ptp", "clk", V(1, 1, 1, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0))), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "clk", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifo", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "mosi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "cmd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0xa, "audio", "rmclk", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "pwm", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d0", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x4, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "audio", "spdifi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "audio-1", "sdi", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "col", V(1, 1, 1, 1, 1, 0, 0))), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d1", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "rts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "txd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "spi", "cs", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "sdio", "d2", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "uart0", "cts", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x3, "uart1", "rxd", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "extclk", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "mii", "crs", V(1, 1, 1, 1, 1, 0, 0))), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "sdio", "d3", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xa, "sata1", "act", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xd, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io0", V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "nand", "io1", V(1, 1, 1, 1, 1, 1, 1))), + MPP_MODE(20, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd0", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d0", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(0, 0, 0, 0, 0, 0, 0))), + MPP_MODE(21, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd1", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d1", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(22, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd2", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d2", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(23, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txd3", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d3", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(24, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd0", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d4", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(25, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd1", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d5", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(26, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd2", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d6", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(27, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxd3", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d7", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(28, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "col", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d8", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "ren", V(0, 0, 0, 0, 0, 0, 1))), + MPP_MODE(29, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclk", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(0, 0, 0, 0, 0, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d9", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "wen", V(0, 0, 0, 0, 0, 0, 1))), + MPP_MODE(30, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxctl", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d10", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(31, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxclk", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d11", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(32, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txclko", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d12", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(33, + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 1, 1, 1, 1, 0, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txctl", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d13", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(34, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "txen", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d14", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "ale", V(0, 0, 0, 0, 0, 0, 1))), + MPP_MODE(35, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 1, 1, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx0ql", V(0, 0, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x3, "ge1", "rxerr", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d15", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xc, "mii", "rxerr", V(1, 1, 1, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "nand", "cen", V(0, 0, 0, 0, 0, 0, 1))), + MPP_MODE(36, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp0", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs1", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifi", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sda", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(37, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp1", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "tx2ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "spdifo", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "twsi1", "sck", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(38, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp2", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx2ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "rmclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d18", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(39, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp3", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-cs0", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "bclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d19", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(40, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp4", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-sck", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdo", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d20", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(41, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp5", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-miso", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "lrclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d21", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(42, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp6", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "spi-mosi", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "mclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d22", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(43, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp7", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "int", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "sdi", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d23", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(44, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(1, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp8", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rst", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x4, "audio", "extclk", V(1, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "clk", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(45, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 1, 1)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "pclk", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "e", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(46, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp10", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "fs", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "hsync", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(47, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp11", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "drx", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(48, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp12", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "dtx", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d16", V(0, 0, 0, 0, 1, 0, 0))), + MPP_MODE(49, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V(0, 0, 0, 1, 0, 1, 1)), + MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0x1, "ts", "mp9", V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0x2, "tdm", "rx0ql", V(0, 0, 0, 1, 1, 0, 0)), + MPP_VAR_FUNCTION(0x5, "ptp", "clk", V(0, 0, 0, 1, 0, 0, 0)), + MPP_VAR_FUNCTION(0xa, "pex", "clkreq", V(0, 0, 0, 0, 1, 0, 0)), + MPP_VAR_FUNCTION(0xb, "lcd", "d17", V(0, 0, 0, 0, 1, 0, 0))), +}; + +static const struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = { + MPP_FUNC_CTRL(0, 44, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 20), + MPP_GPIO_RANGE(1, 35, 35, 10), +}; + +static const struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = { + MPP_FUNC_CTRL(0, 35, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 4), +}; + +static const struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = { + MPP_FUNC_CTRL(0, 49, NULL, mvebu_mmio_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 32), + MPP_GPIO_RANGE(1, 32, 32, 18), +}; + +static struct mvebu_pinctrl_soc_info mv88f6180_info = { + .variant = VARIANT_MV88F6180, + .controls = mv88f6180_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f6180_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f6180_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f6180_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6190_info = { + .variant = VARIANT_MV88F6190, + .controls = mv88f619x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f619x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6192_info = { + .variant = VARIANT_MV88F6192, + .controls = mv88f619x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f619x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f619x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f619x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6281_info = { + .variant = VARIANT_MV88F6281, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f6282_info = { + .variant = VARIANT_MV88F6282, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv98dx4122_info = { + .variant = VARIANT_MV98DX4122, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv98dx1135_info = { + .variant = VARIANT_MV98DX1135, + .controls = mv88f628x_mpp_controls, + .ncontrols = ARRAY_SIZE(mv88f628x_mpp_controls), + .modes = mv88f6xxx_mpp_modes, + .nmodes = ARRAY_SIZE(mv88f6xxx_mpp_modes), + .gpioranges = mv88f628x_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges), +}; + + +static const struct of_device_id kirkwood_pinctrl_of_match[] = { + { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info }, + { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info }, + { .compatible = "marvell,88f6192-pinctrl", .data = &mv88f6192_info }, + { .compatible = "marvell,88f6281-pinctrl", .data = &mv88f6281_info }, + { .compatible = "marvell,88f6282-pinctrl", .data = &mv88f6282_info }, + { .compatible = "marvell,98dx4122-pinctrl", .data = &mv98dx4122_info }, + { .compatible = "marvell,98dx1135-pinctrl", .data = &mv98dx1135_info }, + { } +}; + +static int kirkwood_pinctrl_probe(struct platform_device *pdev) +{ + pdev->dev.platform_data = (void *)device_get_match_data(&pdev->dev); + + return mvebu_pinctrl_simple_mmio_probe(pdev); +} + +static struct platform_driver kirkwood_pinctrl_driver = { + .driver = { + .name = "kirkwood-pinctrl", + .of_match_table = kirkwood_pinctrl_of_match, + }, + .probe = kirkwood_pinctrl_probe, +}; +builtin_platform_driver(kirkwood_pinctrl_driver); diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c new file mode 100644 index 000000000..5ce3d7fcd --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -0,0 +1,844 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell MVEBU pinctrl core driver + * + * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#include <linux/err.h> +#include <linux/gpio/driver.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include "pinctrl-mvebu.h" + +#define MPPS_PER_REG 8 +#define MPP_BITS 4 +#define MPP_MASK 0xf + +struct mvebu_pinctrl_function { + const char *name; + const char **groups; + unsigned num_groups; +}; + +struct mvebu_pinctrl_group { + const char *name; + const struct mvebu_mpp_ctrl *ctrl; + struct mvebu_mpp_ctrl_data *data; + struct mvebu_mpp_ctrl_setting *settings; + unsigned num_settings; + unsigned gid; + unsigned *pins; + unsigned npins; +}; + +struct mvebu_pinctrl { + struct device *dev; + struct pinctrl_dev *pctldev; + struct pinctrl_desc desc; + struct mvebu_pinctrl_group *groups; + unsigned num_groups; + struct mvebu_pinctrl_function *functions; + unsigned num_functions; + u8 variant; +}; + +int mvebu_mmio_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, + unsigned int pid, unsigned long *config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + *config = (readl(data->base + off) >> shift) & MVEBU_MPP_MASK; + + return 0; +} + +int mvebu_mmio_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, + unsigned int pid, unsigned long config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned long reg; + + reg = readl(data->base + off) & ~(MVEBU_MPP_MASK << shift); + writel(reg | (config << shift), data->base + off); + + return 0; +} + +static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_pid( + struct mvebu_pinctrl *pctl, unsigned pid) +{ + unsigned n; + for (n = 0; n < pctl->num_groups; n++) { + if (pid >= pctl->groups[n].pins[0] && + pid < pctl->groups[n].pins[0] + + pctl->groups[n].npins) + return &pctl->groups[n]; + } + return NULL; +} + +static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_name( + struct mvebu_pinctrl *pctl, const char *name) +{ + unsigned n; + + for (n = 0; n < pctl->num_groups; n++) { + if (strcmp(name, pctl->groups[n].name) == 0) + return &pctl->groups[n]; + } + + return NULL; +} + +static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_val( + struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, + unsigned long config) +{ + unsigned n; + + for (n = 0; n < grp->num_settings; n++) { + if (config == grp->settings[n].val) { + if (!pctl->variant || (pctl->variant & + grp->settings[n].variant)) + return &grp->settings[n]; + } + } + + return NULL; +} + +static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_setting_by_name( + struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp, + const char *name) +{ + unsigned n; + + for (n = 0; n < grp->num_settings; n++) { + if (strcmp(name, grp->settings[n].name) == 0) { + if (!pctl->variant || (pctl->variant & + grp->settings[n].variant)) + return &grp->settings[n]; + } + } + + return NULL; +} + +static struct mvebu_mpp_ctrl_setting *mvebu_pinctrl_find_gpio_setting( + struct mvebu_pinctrl *pctl, struct mvebu_pinctrl_group *grp) +{ + unsigned n; + + for (n = 0; n < grp->num_settings; n++) { + if (grp->settings[n].flags & + (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { + if (!pctl->variant || (pctl->variant & + grp->settings[n].variant)) + return &grp->settings[n]; + } + } + + return NULL; +} + +static struct mvebu_pinctrl_function *mvebu_pinctrl_find_function_by_name( + struct mvebu_pinctrl *pctl, const char *name) +{ + unsigned n; + + for (n = 0; n < pctl->num_functions; n++) { + if (strcmp(name, pctl->functions[n].name) == 0) + return &pctl->functions[n]; + } + + return NULL; +} + +static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned gid, unsigned long *config) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; + + if (!grp->ctrl) + return -EINVAL; + + return grp->ctrl->mpp_get(grp->data, grp->pins[0], config); +} + +static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned gid, unsigned long *configs, + unsigned num_configs) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; + int i, ret; + + if (!grp->ctrl) + return -EINVAL; + + for (i = 0; i < num_configs; i++) { + ret = grp->ctrl->mpp_set(grp->data, grp->pins[0], configs[i]); + if (ret) + return ret; + } /* for each config */ + + return 0; +} + +static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned gid) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; + struct mvebu_mpp_ctrl_setting *curr; + unsigned long config; + unsigned n; + + if (mvebu_pinconf_group_get(pctldev, gid, &config)) + return; + + curr = mvebu_pinctrl_find_setting_by_val(pctl, grp, config); + + if (curr) { + seq_printf(s, "current: %s", curr->name); + if (curr->subname) + seq_printf(s, "(%s)", curr->subname); + if (curr->flags & (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { + seq_putc(s, '('); + if (curr->flags & MVEBU_SETTING_GPI) + seq_putc(s, 'i'); + if (curr->flags & MVEBU_SETTING_GPO) + seq_putc(s, 'o'); + seq_putc(s, ')'); + } + } else { + seq_puts(s, "current: UNKNOWN"); + } + + if (grp->num_settings > 1) { + seq_puts(s, ", available = ["); + for (n = 0; n < grp->num_settings; n++) { + if (curr == &grp->settings[n]) + continue; + + /* skip unsupported settings for this variant */ + if (pctl->variant && + !(pctl->variant & grp->settings[n].variant)) + continue; + + seq_printf(s, " %s", grp->settings[n].name); + if (grp->settings[n].subname) + seq_printf(s, "(%s)", grp->settings[n].subname); + if (grp->settings[n].flags & + (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) { + seq_putc(s, '('); + if (grp->settings[n].flags & MVEBU_SETTING_GPI) + seq_putc(s, 'i'); + if (grp->settings[n].flags & MVEBU_SETTING_GPO) + seq_putc(s, 'o'); + seq_putc(s, ')'); + } + } + seq_puts(s, " ]"); + } +} + +static const struct pinconf_ops mvebu_pinconf_ops = { + .pin_config_group_get = mvebu_pinconf_group_get, + .pin_config_group_set = mvebu_pinconf_group_set, + .pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show, +}; + +static int mvebu_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return pctl->num_functions; +} + +static const char *mvebu_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned fid) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + + return pctl->functions[fid].name; +} + +static int mvebu_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned fid, + const char * const **groups, + unsigned * const num_groups) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pctl->functions[fid].groups; + *num_groups = pctl->functions[fid].num_groups; + return 0; +} + +static int mvebu_pinmux_set(struct pinctrl_dev *pctldev, unsigned fid, + unsigned gid) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_function *func = &pctl->functions[fid]; + struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; + struct mvebu_mpp_ctrl_setting *setting; + int ret; + unsigned long config; + + setting = mvebu_pinctrl_find_setting_by_name(pctl, grp, + func->name); + if (!setting) { + dev_err(pctl->dev, + "unable to find setting %s in group %s\n", + func->name, func->groups[gid]); + return -EINVAL; + } + + config = setting->val; + ret = mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); + if (ret) { + dev_err(pctl->dev, "cannot set group %s to %s\n", + func->groups[gid], func->name); + return ret; + } + + return 0; +} + +static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_group *grp; + struct mvebu_mpp_ctrl_setting *setting; + unsigned long config; + + grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); + if (!grp) + return -EINVAL; + + if (grp->ctrl->mpp_gpio_req) + return grp->ctrl->mpp_gpio_req(grp->data, offset); + + setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); + if (!setting) + return -ENOTSUPP; + + config = setting->val; + + return mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); +} + +static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct mvebu_pinctrl_group *grp; + struct mvebu_mpp_ctrl_setting *setting; + + grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); + if (!grp) + return -EINVAL; + + if (grp->ctrl->mpp_gpio_dir) + return grp->ctrl->mpp_gpio_dir(grp->data, offset, input); + + setting = mvebu_pinctrl_find_gpio_setting(pctl, grp); + if (!setting) + return -ENOTSUPP; + + if ((input && (setting->flags & MVEBU_SETTING_GPI)) || + (!input && (setting->flags & MVEBU_SETTING_GPO))) + return 0; + + return -ENOTSUPP; +} + +static const struct pinmux_ops mvebu_pinmux_ops = { + .get_functions_count = mvebu_pinmux_get_funcs_count, + .get_function_name = mvebu_pinmux_get_func_name, + .get_function_groups = mvebu_pinmux_get_groups, + .gpio_request_enable = mvebu_pinmux_gpio_request_enable, + .gpio_set_direction = mvebu_pinmux_gpio_set_direction, + .set_mux = mvebu_pinmux_set, +}; + +static int mvebu_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + return pctl->num_groups; +} + +static const char *mvebu_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned gid) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + return pctl->groups[gid].name; +} + +static int mvebu_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned gid, const unsigned **pins, + unsigned *num_pins) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + *pins = pctl->groups[gid].pins; + *num_pins = pctl->groups[gid].npins; + return 0; +} + +static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *num_maps) +{ + struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + struct property *prop; + const char *function; + const char *group; + int ret, nmaps, n; + + *map = NULL; + *num_maps = 0; + + ret = of_property_read_string(np, "marvell,function", &function); + if (ret) { + dev_err(pctl->dev, + "missing marvell,function in node %pOFn\n", np); + return 0; + } + + nmaps = of_property_count_strings(np, "marvell,pins"); + if (nmaps < 0) { + dev_err(pctl->dev, + "missing marvell,pins in node %pOFn\n", np); + return 0; + } + + *map = kmalloc_objs(**map, nmaps); + if (!*map) + return -ENOMEM; + + n = 0; + of_property_for_each_string(np, "marvell,pins", prop, group) { + struct mvebu_pinctrl_group *grp = + mvebu_pinctrl_find_group_by_name(pctl, group); + + if (!grp) { + dev_err(pctl->dev, "unknown pin %s", group); + continue; + } + + if (!mvebu_pinctrl_find_setting_by_name(pctl, grp, function)) { + dev_err(pctl->dev, "unsupported function %s on pin %s", + function, group); + continue; + } + + (*map)[n].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[n].data.mux.group = group; + (*map)[n].data.mux.function = function; + n++; + } + + *num_maps = nmaps; + + return 0; +} + +static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + kfree(map); +} + +static const struct pinctrl_ops mvebu_pinctrl_ops = { + .get_groups_count = mvebu_pinctrl_get_groups_count, + .get_group_name = mvebu_pinctrl_get_group_name, + .get_group_pins = mvebu_pinctrl_get_group_pins, + .dt_node_to_map = mvebu_pinctrl_dt_node_to_map, + .dt_free_map = mvebu_pinctrl_dt_free_map, +}; + +static int _add_function(struct mvebu_pinctrl_function *funcs, int *funcsize, + const char *name) +{ + if (*funcsize <= 0) + return -EOVERFLOW; + + while (funcs->num_groups) { + /* function already there */ + if (strcmp(funcs->name, name) == 0) { + funcs->num_groups++; + return -EEXIST; + } + funcs++; + } + + /* append new unique function */ + funcs->name = name; + funcs->num_groups = 1; + (*funcsize)--; + + return 0; +} + +static int mvebu_pinctrl_build_functions(struct platform_device *pdev, + struct mvebu_pinctrl *pctl) +{ + struct mvebu_pinctrl_function *funcs; + int num = 0, funcsize = pctl->desc.npins; + int n, s; + + /* we allocate functions for number of pins and hope + * there are fewer unique functions than pins available */ + funcs = devm_kcalloc(&pdev->dev, + funcsize, sizeof(struct mvebu_pinctrl_function), + GFP_KERNEL); + if (!funcs) + return -ENOMEM; + + for (n = 0; n < pctl->num_groups; n++) { + struct mvebu_pinctrl_group *grp = &pctl->groups[n]; + for (s = 0; s < grp->num_settings; s++) { + int ret; + + /* skip unsupported settings on this variant */ + if (pctl->variant && + !(pctl->variant & grp->settings[s].variant)) + continue; + + /* check for unique functions and count groups */ + ret = _add_function(funcs, &funcsize, + grp->settings[s].name); + if (ret == -EOVERFLOW) + dev_err(&pdev->dev, + "More functions than pins(%d)\n", + pctl->desc.npins); + if (ret < 0) + continue; + + num++; + } + } + + pctl->num_functions = num; + pctl->functions = funcs; + + for (n = 0; n < pctl->num_groups; n++) { + struct mvebu_pinctrl_group *grp = &pctl->groups[n]; + for (s = 0; s < grp->num_settings; s++) { + struct mvebu_pinctrl_function *f; + const char **groups; + + /* skip unsupported settings on this variant */ + if (pctl->variant && + !(pctl->variant & grp->settings[s].variant)) + continue; + + f = mvebu_pinctrl_find_function_by_name(pctl, + grp->settings[s].name); + + /* allocate group name array if not done already */ + if (!f->groups) { + f->groups = devm_kcalloc(&pdev->dev, + f->num_groups, + sizeof(char *), + GFP_KERNEL); + if (!f->groups) + return -ENOMEM; + } + + /* find next free group name and assign current name */ + groups = f->groups; + while (*groups) + groups++; + *groups = grp->name; + } + } + + return 0; +} + +int mvebu_pinctrl_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); + struct mvebu_pinctrl *pctl; + struct pinctrl_pin_desc *pdesc; + unsigned gid, n, k; + unsigned size, noname = 0; + char *noname_buf; + void *p; + int ret; + + if (!soc || !soc->controls || !soc->modes) { + dev_err(&pdev->dev, "wrong pinctrl soc info\n"); + return -EINVAL; + } + + pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl), + GFP_KERNEL); + if (!pctl) + return -ENOMEM; + + pctl->desc.name = dev_name(&pdev->dev); + pctl->desc.owner = THIS_MODULE; + pctl->desc.pctlops = &mvebu_pinctrl_ops; + pctl->desc.pmxops = &mvebu_pinmux_ops; + pctl->desc.confops = &mvebu_pinconf_ops; + pctl->variant = soc->variant; + pctl->dev = &pdev->dev; + platform_set_drvdata(pdev, pctl); + + /* count controls and create names for mvebu generic + register controls; also does sanity checks */ + pctl->num_groups = 0; + pctl->desc.npins = 0; + for (n = 0; n < soc->ncontrols; n++) { + const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; + + pctl->desc.npins += ctrl->npins; + /* initialize control's pins[] array */ + for (k = 0; k < ctrl->npins; k++) + ctrl->pins[k] = ctrl->pid + k; + + /* + * We allow to pass controls with NULL name that we treat + * as a range of one-pin groups with generic mvebu register + * controls. + */ + if (!ctrl->name) { + pctl->num_groups += ctrl->npins; + noname += ctrl->npins; + } else { + pctl->num_groups += 1; + } + } + + pdesc = devm_kcalloc(&pdev->dev, + pctl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pdesc) + return -ENOMEM; + + for (n = 0; n < pctl->desc.npins; n++) + pdesc[n].number = n; + pctl->desc.pins = pdesc; + + /* + * allocate groups and name buffers for unnamed groups. + */ + size = pctl->num_groups * sizeof(*pctl->groups) + noname * 8; + p = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pctl->groups = p; + noname_buf = p + pctl->num_groups * sizeof(*pctl->groups); + + /* assign mpp controls to groups */ + gid = 0; + for (n = 0; n < soc->ncontrols; n++) { + const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n]; + struct mvebu_mpp_ctrl_data *data = soc->control_data ? + &soc->control_data[n] : NULL; + + pctl->groups[gid].gid = gid; + pctl->groups[gid].ctrl = ctrl; + pctl->groups[gid].data = data; + pctl->groups[gid].name = ctrl->name; + pctl->groups[gid].pins = ctrl->pins; + pctl->groups[gid].npins = ctrl->npins; + + /* + * We treat unnamed controls as a range of one-pin groups + * with generic mvebu register controls. Use one group for + * each in this range and assign a default group name. + */ + if (!ctrl->name) { + pctl->groups[gid].name = noname_buf; + pctl->groups[gid].npins = 1; + sprintf(noname_buf, "mpp%d", ctrl->pid+0); + noname_buf += 8; + + for (k = 1; k < ctrl->npins; k++) { + gid++; + pctl->groups[gid].gid = gid; + pctl->groups[gid].ctrl = ctrl; + pctl->groups[gid].data = data; + pctl->groups[gid].name = noname_buf; + pctl->groups[gid].pins = &ctrl->pins[k]; + pctl->groups[gid].npins = 1; + sprintf(noname_buf, "mpp%d", ctrl->pid+k); + noname_buf += 8; + } + } + gid++; + } + + /* assign mpp modes to groups */ + for (n = 0; n < soc->nmodes; n++) { + struct mvebu_mpp_mode *mode = &soc->modes[n]; + struct mvebu_mpp_ctrl_setting *set = &mode->settings[0]; + struct mvebu_pinctrl_group *grp; + unsigned num_settings; + unsigned supp_settings; + + for (num_settings = 0, supp_settings = 0; ; set++) { + if (!set->name) + break; + + num_settings++; + + /* skip unsupported settings for this variant */ + if (pctl->variant && !(pctl->variant & set->variant)) + continue; + + supp_settings++; + + /* find gpio/gpo/gpi settings */ + if (strcmp(set->name, "gpio") == 0) + set->flags = MVEBU_SETTING_GPI | + MVEBU_SETTING_GPO; + else if (strcmp(set->name, "gpo") == 0) + set->flags = MVEBU_SETTING_GPO; + else if (strcmp(set->name, "gpi") == 0) + set->flags = MVEBU_SETTING_GPI; + } + + /* skip modes with no settings for this variant */ + if (!supp_settings) + continue; + + grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid); + if (!grp) { + dev_warn(&pdev->dev, "unknown pinctrl group %d\n", + mode->pid); + continue; + } + + grp->settings = mode->settings; + grp->num_settings = num_settings; + } + + ret = mvebu_pinctrl_build_functions(pdev, pctl); + if (ret) { + dev_err(&pdev->dev, "unable to build functions\n"); + return ret; + } + + pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pctl->desc, pctl); + if (IS_ERR(pctl->pctldev)) { + dev_err(&pdev->dev, "unable to register pinctrl driver\n"); + return PTR_ERR(pctl->pctldev); + } + + dev_info(&pdev->dev, "registered pinctrl driver\n"); + + /* register gpio ranges */ + for (n = 0; n < soc->ngpioranges; n++) + pinctrl_add_gpio_range(pctl->pctldev, &soc->gpioranges[n]); + + return 0; +} + +/* + * mvebu_pinctrl_simple_mmio_probe - probe a simple mmio pinctrl + * @pdev: platform device (with platform data already attached) + * + * Initialise a simple (single base address) mmio pinctrl driver, + * assigning the MMIO base address to all mvebu mpp ctrl instances. + */ +int mvebu_pinctrl_simple_mmio_probe(struct platform_device *pdev) +{ + struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); + struct mvebu_mpp_ctrl_data *mpp_data; + void __iomem *base; + int i; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data), + GFP_KERNEL); + if (!mpp_data) + return -ENOMEM; + + for (i = 0; i < soc->ncontrols; i++) + mpp_data[i].base = base; + + soc->control_data = mpp_data; + + return mvebu_pinctrl_probe(pdev); +} + +int mvebu_regmap_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, + unsigned int pid, unsigned long *config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned int val; + int err; + + err = regmap_read(data->regmap.map, data->regmap.offset + off, &val); + if (err) + return err; + + *config = (val >> shift) & MVEBU_MPP_MASK; + + return 0; +} + +int mvebu_regmap_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, + unsigned int pid, unsigned long config) +{ + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + return regmap_update_bits(data->regmap.map, data->regmap.offset + off, + MVEBU_MPP_MASK << shift, config << shift); +} + +int mvebu_pinctrl_simple_regmap_probe(struct platform_device *pdev, + struct device *syscon_dev, u32 offset) +{ + struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); + struct mvebu_mpp_ctrl_data *mpp_data; + struct regmap *regmap; + int i; + + regmap = syscon_node_to_regmap(syscon_dev->of_node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data), + GFP_KERNEL); + if (!mpp_data) + return -ENOMEM; + + for (i = 0; i < soc->ncontrols; i++) { + mpp_data[i].regmap.map = regmap; + mpp_data[i].regmap.offset = offset; + } + + soc->control_data = mpp_data; + + return mvebu_pinctrl_probe(pdev); +} diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h new file mode 100644 index 000000000..13c2b877b --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Marvell MVEBU pinctrl driver + * + * Authors: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + */ + +#ifndef __PINCTRL_MVEBU_H__ +#define __PINCTRL_MVEBU_H__ + +/** + * struct mvebu_mpp_ctrl_data - private data for the mpp ctrl operations + * @base: base address of pinctrl hardware + * @regmap.map: regmap structure + * @regmap.offset: regmap offset + */ +struct mvebu_mpp_ctrl_data { + union { + void __iomem *base; + struct { + struct regmap *map; + u32 offset; + } regmap; + }; +}; + +/** + * struct mvebu_mpp_ctrl - describe a mpp control + * @name: name of the control group + * @pid: first pin id handled by this control + * @npins: number of pins controlled by this control + * @mpp_get: (optional) special function to get mpp setting + * @mpp_set: (optional) special function to set mpp setting + * @mpp_gpio_req: (optional) special function to request gpio + * @mpp_gpio_dir: (optional) special function to set gpio direction + * + * A mpp_ctrl describes a muxable unit, e.g. pin, group of pins, or + * internal function, inside the SoC. Each muxable unit can be switched + * between two or more different settings, e.g. assign mpp pin 13 to + * uart1 or sata. + * + * The mpp_get/_set functions are mandatory and are used to get/set a + * specific mode. The optional mpp_gpio_req/_dir functions can be used + * to allow pin settings with varying gpio pins. + */ +struct mvebu_mpp_ctrl { + const char *name; + u8 pid; + u8 npins; + unsigned *pins; + int (*mpp_get)(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config); + int (*mpp_set)(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config); + int (*mpp_gpio_req)(struct mvebu_mpp_ctrl_data *data, unsigned pid); + int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl_data *data, unsigned pid, + bool input); +}; + +/** + * struct mvebu_mpp_ctrl_setting - describe a mpp ctrl setting + * @val: ctrl setting value + * @name: ctrl setting name, e.g. uart2, spi0 - unique per mpp_mode + * @subname: (optional) additional ctrl setting name, e.g. rts, cts + * @variant: (optional) variant identifier mask + * @flags: (private) flags to store gpi/gpo/gpio capabilities + * + * A ctrl_setting describes a specific internal mux function that a mpp pin + * can be switched to. The value (val) will be written in the corresponding + * register for common mpp pin configuration registers on MVEBU. SoC specific + * mpp_get/_set function may use val to distinguish between different settings. + * + * The name will be used to switch to this setting in DT description, e.g. + * marvell,function = "uart2". subname is only for debugging purposes. + * + * If name is one of "gpi", "gpo", "gpio" gpio capabilities are + * parsed during initialization and stored in flags. + * + * The variant can be used to combine different revisions of one SoC to a + * common pinctrl driver. It is matched (AND) with variant of soc_info to + * determine if a setting is available on the current SoC revision. + */ +struct mvebu_mpp_ctrl_setting { + u8 val; + const char *name; + const char *subname; + u8 variant; + u8 flags; +#define MVEBU_SETTING_GPO (1 << 0) +#define MVEBU_SETTING_GPI (1 << 1) +}; + +/** + * struct mvebu_mpp_mode - link ctrl and settings + * @pid: first pin id handled by this mode + * @settings: list of settings available for this mode + * + * A mode connects all available settings with the corresponding mpp_ctrl + * given by pid. + */ +struct mvebu_mpp_mode { + u8 pid; + struct mvebu_mpp_ctrl_setting *settings; +}; + +/** + * struct mvebu_pinctrl_soc_info - SoC specific info passed to pinctrl-mvebu + * @variant: variant mask of soc_info + * @controls: list of available mvebu_mpp_ctrls + * @control_data: optional array, one entry for each control + * @ncontrols: number of available mvebu_mpp_ctrls + * @modes: list of available mvebu_mpp_modes + * @nmodes: number of available mvebu_mpp_modes + * @gpioranges: list of pinctrl_gpio_ranges + * @ngpioranges: number of available pinctrl_gpio_ranges + * + * This struct describes all pinctrl related information for a specific SoC. + * If variant is unequal 0 it will be matched (AND) with variant of each + * setting and allows to distinguish between different revisions of one SoC. + */ +struct mvebu_pinctrl_soc_info { + u8 variant; + const struct mvebu_mpp_ctrl *controls; + struct mvebu_mpp_ctrl_data *control_data; + int ncontrols; + struct mvebu_mpp_mode *modes; + int nmodes; + struct pinctrl_gpio_range *gpioranges; + int ngpioranges; +}; + +#define MPP_FUNC_CTRL(_idl, _idh, _name, _func) \ + { \ + .name = _name, \ + .pid = _idl, \ + .npins = _idh - _idl + 1, \ + .pins = (unsigned[_idh - _idl + 1]) { }, \ + .mpp_get = _func ## _get, \ + .mpp_set = _func ## _set, \ + .mpp_gpio_req = NULL, \ + .mpp_gpio_dir = NULL, \ + } + +#define MPP_FUNC_GPIO_CTRL(_idl, _idh, _name, _func) \ + { \ + .name = _name, \ + .pid = _idl, \ + .npins = _idh - _idl + 1, \ + .pins = (unsigned[_idh - _idl + 1]) { }, \ + .mpp_get = _func ## _get, \ + .mpp_set = _func ## _set, \ + .mpp_gpio_req = _func ## _gpio_req, \ + .mpp_gpio_dir = _func ## _gpio_dir, \ + } + +#define _MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ + { \ + .val = _val, \ + .name = _name, \ + .subname = _subname, \ + .variant = _mask, \ + .flags = 0, \ + } + +#if defined(CONFIG_DEBUG_FS) +#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ + _MPP_VAR_FUNCTION(_val, _name, _subname, _mask) +#else +#define MPP_VAR_FUNCTION(_val, _name, _subname, _mask) \ + _MPP_VAR_FUNCTION(_val, _name, NULL, _mask) +#endif + +#define MPP_FUNCTION(_val, _name, _subname) \ + MPP_VAR_FUNCTION(_val, _name, _subname, (u8)-1) + +#define MPP_MODE(_id, ...) \ + { \ + .pid = _id, \ + .settings = (struct mvebu_mpp_ctrl_setting[]){ \ + __VA_ARGS__, { } }, \ + } + +#define MPP_GPIO_RANGE(_id, _pinbase, _gpiobase, _npins) \ + { \ + .name = "mvebu-gpio", \ + .id = _id, \ + .pin_base = _pinbase, \ + .base = _gpiobase, \ + .npins = _npins, \ + } + +#define MVEBU_MPPS_PER_REG 8 +#define MVEBU_MPP_BITS 4 +#define MVEBU_MPP_MASK 0xf + +int mvebu_mmio_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config); +int mvebu_mmio_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config); +int mvebu_regmap_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long *config); +int mvebu_regmap_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid, + unsigned long config); + +int mvebu_pinctrl_probe(struct platform_device *pdev); +int mvebu_pinctrl_simple_mmio_probe(struct platform_device *pdev); +int mvebu_pinctrl_simple_regmap_probe(struct platform_device *pdev, + struct device *syscon_dev, u32 offset); + +#endif diff --git a/drivers/pinctrl/mvebu/pinctrl-orion.c b/drivers/pinctrl/mvebu/pinctrl-orion.c new file mode 100644 index 000000000..2b6ab7f2a --- /dev/null +++ b/drivers/pinctrl/mvebu/pinctrl-orion.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Marvell Orion pinctrl driver based on mvebu pinctrl core + * + * Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * + * The first 16 MPP pins on Orion are easy to handle: they are + * configured through 2 consecutive registers, located at the base + * address of the MPP device. + * + * However the last 4 MPP pins are handled by a register at offset + * 0x50 from the base address, so it is not consecutive with the first + * two registers. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/property.h> + +#include "pinctrl-mvebu.h" + +static void __iomem *mpp_base; +static void __iomem *high_mpp_base; + +static int orion_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, + unsigned pid, unsigned long *config) +{ + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + if (pid < 16) { + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + *config = (readl(mpp_base + off) >> shift) & MVEBU_MPP_MASK; + } + else { + *config = (readl(high_mpp_base) >> shift) & MVEBU_MPP_MASK; + } + + return 0; +} + +static int orion_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, + unsigned pid, unsigned long config) +{ + unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + + if (pid < 16) { + unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS; + u32 reg = readl(mpp_base + off) & ~(MVEBU_MPP_MASK << shift); + writel(reg | (config << shift), mpp_base + off); + } + else { + u32 reg = readl(high_mpp_base) & ~(MVEBU_MPP_MASK << shift); + writel(reg | (config << shift), high_mpp_base); + } + + return 0; +} + +#define V(f5181, f5182, f5281) \ + ((f5181 << 0) | (f5182 << 1) | (f5281 << 2)) + +enum orion_variant { + V_5181 = V(1, 0, 0), + V_5182 = V(0, 1, 0), + V_5281 = V(0, 0, 1), + V_ALL = V(1, 1, 1), +}; + +static struct mvebu_mpp_mode orion_mpp_modes[] = { + MPP_MODE(0, + MPP_VAR_FUNCTION(0x0, "pcie", "rstout", V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req2", V_ALL), + MPP_VAR_FUNCTION(0x3, "gpio", NULL, V_ALL)), + MPP_MODE(1, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt2", V_ALL)), + MPP_MODE(2, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req3", V_ALL), + MPP_VAR_FUNCTION(0x3, "pci-1", "pme", V_ALL)), + MPP_MODE(3, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt3", V_ALL)), + MPP_MODE(4, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req4", V_ALL), + MPP_VAR_FUNCTION(0x4, "bootnand", "re", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "prsnt", V_5182)), + MPP_MODE(5, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt4", V_ALL), + MPP_VAR_FUNCTION(0x4, "bootnand", "we", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "prsnt", V_5182)), + MPP_MODE(6, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "req5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re0", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181), + MPP_VAR_FUNCTION(0x5, "sata0", "act", V_5182)), + MPP_MODE(7, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x2, "pci", "gnt5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we0", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "pci-1", "clk", V_5181), + MPP_VAR_FUNCTION(0x5, "sata1", "act", V_5182)), + MPP_MODE(8, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "col", V_ALL)), + MPP_MODE(9, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "rxerr", V_ALL)), + MPP_MODE(10, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "crs", V_ALL)), + MPP_MODE(11, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txerr", V_ALL)), + MPP_MODE(12, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd4", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re1", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "ledprsnt", V_5182)), + MPP_MODE(13, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd5", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we1", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "ledprsnt", V_5182)), + MPP_MODE(14, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd6", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "re2", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata0", "ledact", V_5182)), + MPP_MODE(15, + MPP_VAR_FUNCTION(0x0, "gpio", NULL, V_ALL), + MPP_VAR_FUNCTION(0x1, "ge", "txd7", V_ALL), + MPP_VAR_FUNCTION(0x4, "nand", "we2", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x5, "sata1", "ledact", V_5182)), + MPP_MODE(16, + MPP_VAR_FUNCTION(0x0, "uart1", "rxd", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd4", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(17, + MPP_VAR_FUNCTION(0x0, "uart1", "txd", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd5", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(18, + MPP_VAR_FUNCTION(0x0, "uart1", "cts", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd6", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), + MPP_MODE(19, + MPP_VAR_FUNCTION(0x0, "uart1", "rts", V_5182 | V_5281), + MPP_VAR_FUNCTION(0x1, "ge", "rxd7", V_ALL), + MPP_VAR_FUNCTION(0x5, "gpio", NULL, V_5182)), +}; + +static const struct mvebu_mpp_ctrl orion_mpp_controls[] = { + MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl), +}; + +static struct pinctrl_gpio_range mv88f5181_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 16), +}; + +static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 19), +}; + +static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = { + MPP_GPIO_RANGE(0, 0, 0, 16), +}; + +static struct mvebu_pinctrl_soc_info mv88f5181_info = { + .variant = V_5181, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5181_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5181_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f5182_info = { + .variant = V_5182, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5182_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5182_gpio_ranges), +}; + +static struct mvebu_pinctrl_soc_info mv88f5281_info = { + .variant = V_5281, + .controls = orion_mpp_controls, + .ncontrols = ARRAY_SIZE(orion_mpp_controls), + .modes = orion_mpp_modes, + .nmodes = ARRAY_SIZE(orion_mpp_modes), + .gpioranges = mv88f5281_gpio_ranges, + .ngpioranges = ARRAY_SIZE(mv88f5281_gpio_ranges), +}; + +/* + * There are multiple variants of the Orion SoCs, but in terms of pin + * muxing, they are identical. + */ +static const struct of_device_id orion_pinctrl_of_match[] = { + { .compatible = "marvell,88f5181-pinctrl", .data = &mv88f5181_info }, + { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181_info }, + { .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info }, + { .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info }, + { } +}; + +static int orion_pinctrl_probe(struct platform_device *pdev) +{ + pdev->dev.platform_data = (void*)device_get_match_data(&pdev->dev); + + mpp_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mpp_base)) + return PTR_ERR(mpp_base); + + high_mpp_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(high_mpp_base)) + return PTR_ERR(high_mpp_base); + + return mvebu_pinctrl_probe(pdev); +} + +static struct platform_driver orion_pinctrl_driver = { + .driver = { + .name = "orion-pinctrl", + .of_match_table = of_match_ptr(orion_pinctrl_of_match), + }, + .probe = orion_pinctrl_probe, +}; +builtin_platform_driver(orion_pinctrl_driver); |
