pinctrl: MediaTek: add pinctrl driver for MT7629 SoC
authorRyder Lee <ryder.lee@mediatek.com>
Thu, 15 Nov 2018 02:07:58 +0000 (10:07 +0800)
committerTom Rini <trini@konsulko.com>
Thu, 29 Nov 2018 04:04:52 +0000 (23:04 -0500)
This patch adds pinctrl support for MT7629 SoC. The IO core found on
the SoC has the registers for pinctrl, pinconf and gpio mixed up in
the same register range.  Hence the driver also implements the gpio
functionality through UCLASS_GPIO.

This also creates a common file as there might be other chips that use
the same binding and driver, then being a little more abstract could
help in the long run.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
arch/arm/include/asm/arch-mediatek/gpio.h [new file with mode: 0644]
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/mediatek/Kconfig [new file with mode: 0644]
drivers/pinctrl/mediatek/Makefile [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mt7629.c [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mtk-common.c [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mtk-common.h [new file with mode: 0644]

diff --git a/arch/arm/include/asm/arch-mediatek/gpio.h b/arch/arm/include/asm/arch-mediatek/gpio.h
new file mode 100644 (file)
index 0000000..4ea1020
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __MEDIATEK_GPIO_H
+#define __MEDIATEK_GPIO_H
+
+#endif /* __MEDIATEK_GPIO_H */
index ad0b8daba622e30024a45b49d89abe7c676c2f2c..7e6fad305aebc1d6fe6e15d352cba8e7c40814b2 100644 (file)
@@ -301,6 +301,7 @@ config ASPEED_AST2500_PINCTRL
 endif
 
 source "drivers/pinctrl/meson/Kconfig"
+source "drivers/pinctrl/mediatek/Kconfig"
 source "drivers/pinctrl/nxp/Kconfig"
 source "drivers/pinctrl/renesas/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
index a3a6c6d163b3d04a19a8b937ef4147964d5d3b32..293bad3a950bc97fdacca0b63253030a9e12f595 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_UNIPHIER)        += uniphier/
 obj-$(CONFIG_PINCTRL_PIC32)    += pinctrl_pic32.o
 obj-$(CONFIG_PINCTRL_EXYNOS)   += exynos/
 obj-$(CONFIG_PINCTRL_MESON)    += meson/
+obj-$(CONFIG_PINCTRL_MTK)      += mediatek/
 obj-$(CONFIG_ARCH_MVEBU)       += mvebu/
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
 obj-$(CONFIG_PINCTRL_STI)      += pinctrl-sti.o
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
new file mode 100644 (file)
index 0000000..e0145b1
--- /dev/null
@@ -0,0 +1,11 @@
+if ARCH_MEDIATEK
+
+config PINCTRL_MTK
+       depends on PINCTRL_GENERIC
+       bool
+
+config PINCTRL_MT7629
+       bool "MT7629 SoC pinctrl driver"
+       select PINCTRL_MTK
+
+endif
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
new file mode 100644 (file)
index 0000000..cbf0765
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+# Core
+obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
+
+# SoC Drivers
+obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
new file mode 100644 (file)
index 0000000..aa6d1c2
--- /dev/null
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <dm.h>
+
+#include "pinctrl-mtk-common.h"
+
+#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)  \
+       PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,       \
+                      _x_bits, 32, false)
+
+#define MT7629_PIN(_number, _name)     MTK_PIN(_number, _name, DRV_GRP1)
+
+static const struct mtk_pin_field_calc mt7629_pin_mode_range[] = {
+       PIN_FIELD(0, 78, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_dir_range[] = {
+       PIN_FIELD(0, 78, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_di_range[] = {
+       PIN_FIELD(0, 78, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_do_range[] = {
+       PIN_FIELD(0, 78, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_ies_range[] = {
+       PIN_FIELD(0, 10, 0x1000, 0x10, 0, 1),
+       PIN_FIELD(11, 18, 0x2000, 0x10, 0, 1),
+       PIN_FIELD(19, 32, 0x3000, 0x10, 0, 1),
+       PIN_FIELD(33, 48, 0x4000, 0x10, 0, 1),
+       PIN_FIELD(49, 50, 0x5000, 0x10, 0, 1),
+       PIN_FIELD(51, 69, 0x6000, 0x10, 0, 1),
+       PIN_FIELD(70, 78, 0x7000, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_smt_range[] = {
+       PIN_FIELD(0, 10, 0x1100, 0x10, 0, 1),
+       PIN_FIELD(11, 18, 0x2100, 0x10, 0, 1),
+       PIN_FIELD(19, 32, 0x3100, 0x10, 0, 1),
+       PIN_FIELD(33, 48, 0x4100, 0x10, 0, 1),
+       PIN_FIELD(49, 50, 0x5100, 0x10, 0, 1),
+       PIN_FIELD(51, 69, 0x6100, 0x10, 0, 1),
+       PIN_FIELD(70, 78, 0x7100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_pullen_range[] = {
+       PIN_FIELD(0, 10, 0x1400, 0x10, 0, 1),
+       PIN_FIELD(11, 18, 0x2400, 0x10, 0, 1),
+       PIN_FIELD(19, 32, 0x3400, 0x10, 0, 1),
+       PIN_FIELD(33, 48, 0x4400, 0x10, 0, 1),
+       PIN_FIELD(49, 50, 0x5400, 0x10, 0, 1),
+       PIN_FIELD(51, 69, 0x6400, 0x10, 0, 1),
+       PIN_FIELD(70, 78, 0x7400, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_pullsel_range[] = {
+       PIN_FIELD(0, 10, 0x1500, 0x10, 0, 1),
+       PIN_FIELD(11, 18, 0x2500, 0x10, 0, 1),
+       PIN_FIELD(19, 32, 0x3500, 0x10, 0, 1),
+       PIN_FIELD(33, 48, 0x4500, 0x10, 0, 1),
+       PIN_FIELD(49, 50, 0x5500, 0x10, 0, 1),
+       PIN_FIELD(51, 69, 0x6500, 0x10, 0, 1),
+       PIN_FIELD(70, 78, 0x7500, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_drv_range[] = {
+       PIN_FIELD(0, 10, 0x1600, 0x10, 0, 4),
+       PIN_FIELD(11, 18, 0x2600, 0x10, 0, 4),
+       PIN_FIELD(19, 32, 0x3600, 0x10, 0, 4),
+       PIN_FIELD(33, 48, 0x4600, 0x10, 0, 4),
+       PIN_FIELD(49, 50, 0x5600, 0x10, 0, 4),
+       PIN_FIELD(51, 69, 0x6600, 0x10, 0, 4),
+       PIN_FIELD(70, 78, 0x7600, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_reg_calc mt7629_reg_cals[] = {
+       [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7629_pin_mode_range),
+       [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7629_pin_dir_range),
+       [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7629_pin_di_range),
+       [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7629_pin_do_range),
+       [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7629_pin_ies_range),
+       [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7629_pin_smt_range),
+       [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7629_pin_pullsel_range),
+       [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7629_pin_pullen_range),
+       [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7629_pin_drv_range),
+};
+
+static const struct mtk_pin_desc mt7629_pins[] = {
+       MT7629_PIN(0, "TOP_5G_CLK"),
+       MT7629_PIN(1, "TOP_5G_DATA"),
+       MT7629_PIN(2, "WF0_5G_HB0"),
+       MT7629_PIN(3, "WF0_5G_HB1"),
+       MT7629_PIN(4, "WF0_5G_HB2"),
+       MT7629_PIN(5, "WF0_5G_HB3"),
+       MT7629_PIN(6, "WF0_5G_HB4"),
+       MT7629_PIN(7, "WF0_5G_HB5"),
+       MT7629_PIN(8, "WF0_5G_HB6"),
+       MT7629_PIN(9, "XO_REQ"),
+       MT7629_PIN(10, "TOP_RST_N"),
+       MT7629_PIN(11, "SYS_WATCHDOG"),
+       MT7629_PIN(12, "EPHY_LED0_N_JTDO"),
+       MT7629_PIN(13, "EPHY_LED1_N_JTDI"),
+       MT7629_PIN(14, "EPHY_LED2_N_JTMS"),
+       MT7629_PIN(15, "EPHY_LED3_N_JTCLK"),
+       MT7629_PIN(16, "EPHY_LED4_N_JTRST_N"),
+       MT7629_PIN(17, "WF2G_LED_N"),
+       MT7629_PIN(18, "WF5G_LED_N"),
+       MT7629_PIN(19, "I2C_SDA"),
+       MT7629_PIN(20, "I2C_SCL"),
+       MT7629_PIN(21, "GPIO_9"),
+       MT7629_PIN(22, "GPIO_10"),
+       MT7629_PIN(23, "GPIO_11"),
+       MT7629_PIN(24, "GPIO_12"),
+       MT7629_PIN(25, "UART1_TXD"),
+       MT7629_PIN(26, "UART1_RXD"),
+       MT7629_PIN(27, "UART1_CTS"),
+       MT7629_PIN(28, "UART1_RTS"),
+       MT7629_PIN(29, "UART2_TXD"),
+       MT7629_PIN(30, "UART2_RXD"),
+       MT7629_PIN(31, "UART2_CTS"),
+       MT7629_PIN(32, "UART2_RTS"),
+       MT7629_PIN(33, "MDI_TP_P1"),
+       MT7629_PIN(34, "MDI_TN_P1"),
+       MT7629_PIN(35, "MDI_RP_P1"),
+       MT7629_PIN(36, "MDI_RN_P1"),
+       MT7629_PIN(37, "MDI_RP_P2"),
+       MT7629_PIN(38, "MDI_RN_P2"),
+       MT7629_PIN(39, "MDI_TP_P2"),
+       MT7629_PIN(40, "MDI_TN_P2"),
+       MT7629_PIN(41, "MDI_TP_P3"),
+       MT7629_PIN(42, "MDI_TN_P3"),
+       MT7629_PIN(43, "MDI_RP_P3"),
+       MT7629_PIN(44, "MDI_RN_P3"),
+       MT7629_PIN(45, "MDI_RP_P4"),
+       MT7629_PIN(46, "MDI_RN_P4"),
+       MT7629_PIN(47, "MDI_TP_P4"),
+       MT7629_PIN(48, "MDI_TN_P4"),
+       MT7629_PIN(49, "SMI_MDC"),
+       MT7629_PIN(50, "SMI_MDIO"),
+       MT7629_PIN(51, "PCIE_PERESET_N"),
+       MT7629_PIN(52, "PWM_0"),
+       MT7629_PIN(53, "GPIO_0"),
+       MT7629_PIN(54, "GPIO_1"),
+       MT7629_PIN(55, "GPIO_2"),
+       MT7629_PIN(56, "GPIO_3"),
+       MT7629_PIN(57, "GPIO_4"),
+       MT7629_PIN(58, "GPIO_5"),
+       MT7629_PIN(59, "GPIO_6"),
+       MT7629_PIN(60, "GPIO_7"),
+       MT7629_PIN(61, "GPIO_8"),
+       MT7629_PIN(62, "SPI_CLK"),
+       MT7629_PIN(63, "SPI_CS"),
+       MT7629_PIN(64, "SPI_MOSI"),
+       MT7629_PIN(65, "SPI_MISO"),
+       MT7629_PIN(66, "SPI_WP"),
+       MT7629_PIN(67, "SPI_HOLD"),
+       MT7629_PIN(68, "UART0_TXD"),
+       MT7629_PIN(69, "UART0_RXD"),
+       MT7629_PIN(70, "TOP_2G_CLK"),
+       MT7629_PIN(71, "TOP_2G_DATA"),
+       MT7629_PIN(72, "WF0_2G_HB0"),
+       MT7629_PIN(73, "WF0_2G_HB1"),
+       MT7629_PIN(74, "WF0_2G_HB2"),
+       MT7629_PIN(75, "WF0_2G_HB3"),
+       MT7629_PIN(76, "WF0_2G_HB4"),
+       MT7629_PIN(77, "WF0_2G_HB5"),
+       MT7629_PIN(78, "WF0_2G_HB6"),
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+/* WF 5G */
+static int mt7629_wf0_5g_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };
+static int mt7629_wf0_5g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* LED for EPHY */
+static int mt7629_ephy_leds_pins[] = { 12, 13, 14, 15, 16, 17, 18, };
+static int mt7629_ephy_leds_funcs[] = { 1, 1, 1, 1, 1, 1, 1, };
+static int mt7629_ephy_led0_pins[] = { 12, };
+static int mt7629_ephy_led0_funcs[] = { 1, };
+static int mt7629_ephy_led1_pins[] = { 13, };
+static int mt7629_ephy_led1_funcs[] = { 1, };
+static int mt7629_ephy_led2_pins[] = { 14, };
+static int mt7629_ephy_led2_funcs[] = { 1, };
+static int mt7629_ephy_led3_pins[] = { 15, };
+static int mt7629_ephy_led3_funcs[] = { 1, };
+static int mt7629_ephy_led4_pins[] = { 16, };
+static int mt7629_ephy_led4_funcs[] = { 1, };
+static int mt7629_wf2g_led_pins[] = { 17, };
+static int mt7629_wf2g_led_funcs[] = { 1, };
+static int mt7629_wf5g_led_pins[] = { 18, };
+static int mt7629_wf5g_led_funcs[] = { 1, };
+
+/* Watchdog */
+static int mt7629_watchdog_pins[] = { 11, };
+static int mt7629_watchdog_funcs[] = { 1, };
+
+/* LED for GPHY */
+static int mt7629_gphy_leds_0_pins[] = { 21, 22, 23, };
+static int mt7629_gphy_leds_0_funcs[] = { 2, 2, 2, };
+static int mt7629_gphy_led1_0_pins[] = { 21, };
+static int mt7629_gphy_led1_0_funcs[] = { 2, };
+static int mt7629_gphy_led2_0_pins[] = { 22, };
+static int mt7629_gphy_led2_0_funcs[] = { 2, };
+static int mt7629_gphy_led3_0_pins[] = { 23, };
+static int mt7629_gphy_led3_0_funcs[] = { 2, };
+static int mt7629_gphy_leds_1_pins[] = { 57, 58, 59, };
+static int mt7629_gphy_leds_1_funcs[] = { 1, 1, 1, };
+static int mt7629_gphy_led1_1_pins[] = { 57, };
+static int mt7629_gphy_led1_1_funcs[] = { 1, };
+static int mt7629_gphy_led2_1_pins[] = { 58, };
+static int mt7629_gphy_led2_1_funcs[] = { 1, };
+static int mt7629_gphy_led3_1_pins[] = { 59, };
+static int mt7629_gphy_led3_1_funcs[] = { 1, };
+
+/* I2C */
+static int mt7629_i2c_0_pins[] = { 19, 20, };
+static int mt7629_i2c_0_funcs[] = { 1, 1, };
+static int mt7629_i2c_1_pins[] = { 53, 54, };
+static int mt7629_i2c_1_funcs[] = { 1, 1, };
+
+/* SPI */
+static int mt7629_spi_0_pins[] = { 21, 22, 23, 24, };
+static int mt7629_spi_0_funcs[] = { 1, 1, 1, 1, };
+static int mt7629_spi_1_pins[] = { 62, 63, 64, 65, };
+static int mt7629_spi_1_funcs[] = { 1, 1, 1, 1, };
+static int mt7629_spi_wp_pins[] = { 66, };
+static int mt7629_spi_wp_funcs[] = { 1, };
+static int mt7629_spi_hold_pins[] = { 67, };
+static int mt7629_spi_hold_funcs[] = { 1, };
+
+/* UART */
+static int mt7629_uart1_0_txd_rxd_pins[] = { 25, 26, };
+static int mt7629_uart1_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7629_uart1_1_txd_rxd_pins[] = { 53, 54, };
+static int mt7629_uart1_1_txd_rxd_funcs[] = { 2, 2, };
+static int mt7629_uart2_0_txd_rxd_pins[] = { 29, 30, };
+static int mt7629_uart2_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7629_uart2_1_txd_rxd_pins[] = { 57, 58, };
+static int mt7629_uart2_1_txd_rxd_funcs[] = { 2, 2, };
+static int mt7629_uart1_0_cts_rts_pins[] = { 27, 28, };
+static int mt7629_uart1_0_cts_rts_funcs[] = { 1, 1, };
+static int mt7629_uart1_1_cts_rts_pins[] = { 55, 56, };
+static int mt7629_uart1_1_cts_rts_funcs[] = { 2, 2, };
+static int mt7629_uart2_0_cts_rts_pins[] = { 31, 32, };
+static int mt7629_uart2_0_cts_rts_funcs[] = { 1, 1, };
+static int mt7629_uart2_1_cts_rts_pins[] = { 59, 60, };
+static int mt7629_uart2_1_cts_rts_funcs[] = { 2, 2, };
+static int mt7629_uart0_txd_rxd_pins[] = { 68, 69, };
+static int mt7629_uart0_txd_rxd_funcs[] = { 1, 1, };
+
+/* MDC/MDIO */
+static int mt7629_mdc_mdio_pins[] = { 49, 50, };
+static int mt7629_mdc_mdio_funcs[] = { 1, 1, };
+
+/* PCIE */
+static int mt7629_pcie_pereset_pins[] = { 51, };
+static int mt7629_pcie_pereset_funcs[] = { 1, };
+static int mt7629_pcie_wake_pins[] = { 55, };
+static int mt7629_pcie_wake_funcs[] = { 1, };
+static int mt7629_pcie_clkreq_pins[] = { 56, };
+static int mt7629_pcie_clkreq_funcs[] = { 1, };
+
+/* PWM */
+static int mt7629_pwm_0_pins[] = { 52, };
+static int mt7629_pwm_0_funcs[] = { 1, };
+static int mt7629_pwm_1_pins[] = { 61, };
+static int mt7629_pwm_1_funcs[] = { 2, };
+
+/* WF 2G */
+static int mt7629_wf0_2g_pins[] = { 70, 71, 72, 73, 74, 75, 76, 77, 78, };
+static int mt7629_wf0_2g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* SNFI */
+static int mt7629_snfi_pins[] = { 62, 63, 64, 65, 66, 67 };
+static int mt7629_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* SPI NOR */
+static int mt7629_snor_pins[] = { 62, 63, 64, 65, 66, 67 };
+static int mt7629_snor_funcs[] = { 1, 1, 1, 1, 1, 1 };
+
+static const struct mtk_group_desc mt7629_groups[] = {
+       PINCTRL_PIN_GROUP("wf0_5g", mt7629_wf0_5g),
+       PINCTRL_PIN_GROUP("ephy_leds", mt7629_ephy_leds),
+       PINCTRL_PIN_GROUP("ephy_led0", mt7629_ephy_led0),
+       PINCTRL_PIN_GROUP("ephy_led1", mt7629_ephy_led1),
+       PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2),
+       PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3),
+       PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4),
+       PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led),
+       PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led),
+       PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog),
+       PINCTRL_PIN_GROUP("gphy_leds_0", mt7629_gphy_leds_0),
+       PINCTRL_PIN_GROUP("gphy_led1_0", mt7629_gphy_led1_0),
+       PINCTRL_PIN_GROUP("gphy_led2_0", mt7629_gphy_led2_0),
+       PINCTRL_PIN_GROUP("gphy_led3_0", mt7629_gphy_led3_0),
+       PINCTRL_PIN_GROUP("gphy_leds_1", mt7629_gphy_leds_1),
+       PINCTRL_PIN_GROUP("gphy_led1_1", mt7629_gphy_led1_1),
+       PINCTRL_PIN_GROUP("gphy_led2_1", mt7629_gphy_led2_1),
+       PINCTRL_PIN_GROUP("gphy_led3_1", mt7629_gphy_led3_1),
+       PINCTRL_PIN_GROUP("i2c_0", mt7629_i2c_0),
+       PINCTRL_PIN_GROUP("i2c_1", mt7629_i2c_1),
+       PINCTRL_PIN_GROUP("spi_0", mt7629_spi_0),
+       PINCTRL_PIN_GROUP("spi_1", mt7629_spi_1),
+       PINCTRL_PIN_GROUP("spi_wp", mt7629_spi_wp),
+       PINCTRL_PIN_GROUP("spi_hold", mt7629_spi_hold),
+       PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7629_uart1_0_txd_rxd),
+       PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7629_uart1_1_txd_rxd),
+       PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7629_uart2_0_txd_rxd),
+       PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7629_uart2_1_txd_rxd),
+       PINCTRL_PIN_GROUP("uart1_0_cts_rts", mt7629_uart1_0_cts_rts),
+       PINCTRL_PIN_GROUP("uart1_1_cts_rts", mt7629_uart1_1_cts_rts),
+       PINCTRL_PIN_GROUP("uart2_0_cts_rts", mt7629_uart2_0_cts_rts),
+       PINCTRL_PIN_GROUP("uart2_1_cts_rts", mt7629_uart2_1_cts_rts),
+       PINCTRL_PIN_GROUP("uart0_txd_rxd", mt7629_uart0_txd_rxd),
+       PINCTRL_PIN_GROUP("mdc_mdio", mt7629_mdc_mdio),
+       PINCTRL_PIN_GROUP("pcie_pereset", mt7629_pcie_pereset),
+       PINCTRL_PIN_GROUP("pcie_wake", mt7629_pcie_wake),
+       PINCTRL_PIN_GROUP("pcie_clkreq", mt7629_pcie_clkreq),
+       PINCTRL_PIN_GROUP("pwm_0", mt7629_pwm_0),
+       PINCTRL_PIN_GROUP("pwm_1", mt7629_pwm_1),
+       PINCTRL_PIN_GROUP("wf0_2g", mt7629_wf0_2g),
+       PINCTRL_PIN_GROUP("snfi", mt7629_snfi),
+       PINCTRL_PIN_GROUP("spi_nor", mt7629_snor),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *const mt7629_ethernet_groups[] = { "mdc_mdio", };
+static const char *const mt7629_i2c_groups[] = { "i2c_0", "i2c_1", };
+static const char *const mt7629_led_groups[] = { "ephy_leds", "ephy_led0",
+                                               "ephy_led1", "ephy_led2",
+                                               "ephy_led3", "ephy_led4",
+                                               "wf2g_led", "wf5g_led",
+                                               "gphy_leds_0", "gphy_led1_0",
+                                               "gphy_led2_0", "gphy_led3_0",
+                                               "gphy_leds_1", "gphy_led1_1",
+                                               "gphy_led2_1", "gphy_led3_1",};
+static const char *const mt7629_pcie_groups[] = { "pcie_pereset", "pcie_wake",
+                                               "pcie_clkreq", };
+static const char *const mt7629_pwm_groups[] = { "pwm_0", "pwm_1", };
+static const char *const mt7629_spi_groups[] = { "spi_0", "spi_1", "spi_wp",
+                                               "spi_hold", };
+static const char *const mt7629_uart_groups[] = { "uart1_0_txd_rxd",
+                                               "uart1_1_txd_rxd",
+                                               "uart2_0_txd_rxd",
+                                               "uart2_1_txd_rxd",
+                                               "uart1_0_cts_rts",
+                                               "uart1_1_cts_rts",
+                                               "uart2_0_cts_rts",
+                                               "uart2_1_cts_rts",
+                                               "uart0_txd_rxd", };
+static const char *const mt7629_wdt_groups[] = { "watchdog", };
+static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", };
+static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" };
+
+static const struct mtk_function_desc mt7629_functions[] = {
+       {"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)},
+       {"i2c", mt7629_i2c_groups, ARRAY_SIZE(mt7629_i2c_groups)},
+       {"led", mt7629_led_groups, ARRAY_SIZE(mt7629_led_groups)},
+       {"pcie", mt7629_pcie_groups, ARRAY_SIZE(mt7629_pcie_groups)},
+       {"pwm", mt7629_pwm_groups, ARRAY_SIZE(mt7629_pwm_groups)},
+       {"spi", mt7629_spi_groups, ARRAY_SIZE(mt7629_spi_groups)},
+       {"uart", mt7629_uart_groups, ARRAY_SIZE(mt7629_uart_groups)},
+       {"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)},
+       {"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)},
+       {"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)},
+};
+
+static struct mtk_pinctrl_soc mt7629_data = {
+       .name = "mt7629_pinctrl",
+       .reg_cal = mt7629_reg_cals,
+       .pins = mt7629_pins,
+       .npins = ARRAY_SIZE(mt7629_pins),
+       .grps = mt7629_groups,
+       .ngrps = ARRAY_SIZE(mt7629_groups),
+       .funcs = mt7629_functions,
+       .nfuncs = ARRAY_SIZE(mt7629_functions),
+};
+
+static int mtk_pinctrl_mt7629_probe(struct udevice *dev)
+{
+       return mtk_pinctrl_common_probe(dev, &mt7629_data);
+}
+
+static const struct udevice_id mt7629_pctrl_match[] = {
+       { .compatible = "mediatek,mt7629-pinctrl" },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7629_pinctrl) = {
+       .name = "mt7629_pinctrl",
+       .id = UCLASS_PINCTRL,
+       .of_match = mt7629_pctrl_match,
+       .ops = &mtk_pinctrl_ops,
+       .probe = mtk_pinctrl_mt7629_probe,
+       .priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
new file mode 100644 (file)
index 0000000..938cc75
--- /dev/null
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+#include "pinctrl-mtk-common.h"
+
+/**
+ * struct mtk_drive_desc - the structure that holds the information
+ *                         of the driving current
+ * @min:       the minimum current of this group
+ * @max:       the maximum current of this group
+ * @step:      the step current of this group
+ * @scal:      the weight factor
+ *
+ * formula: output = ((input) / step - 1) * scal
+ */
+struct mtk_drive_desc {
+       u8 min;
+       u8 max;
+       u8 step;
+       u8 scal;
+};
+
+/* The groups of drive strength */
+static const struct mtk_drive_desc mtk_drive[] = {
+       [DRV_GRP0] = { 4, 16, 4, 1 },
+       [DRV_GRP1] = { 4, 16, 4, 2 },
+       [DRV_GRP2] = { 2, 8, 2, 1 },
+       [DRV_GRP3] = { 2, 8, 2, 2 },
+       [DRV_GRP4] = { 2, 16, 2, 1 },
+};
+
+static const char *mtk_pinctrl_dummy_name = "_dummy";
+
+static void mtk_w32(struct udevice *dev, u32 reg, u32 val)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       __raw_writel(val, priv->base + reg);
+}
+
+static u32 mtk_r32(struct udevice *dev, u32 reg)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return __raw_readl(priv->base + reg);
+}
+
+static inline int get_count_order(unsigned int count)
+{
+       int order;
+
+       order = fls(count) - 1;
+       if (count & (count - 1))
+               order++;
+       return order;
+}
+
+void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set)
+{
+       u32 val;
+
+       val = mtk_r32(dev, reg);
+       val &= ~mask;
+       val |= set;
+       mtk_w32(dev, reg, val);
+}
+
+static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin,
+                                  const struct mtk_pin_reg_calc *rc,
+                                  struct mtk_pin_field *pfd)
+{
+       const struct mtk_pin_field_calc *c, *e;
+       u32 bits;
+
+       c = rc->range;
+       e = c + rc->nranges;
+
+       while (c < e) {
+               if (pin >= c->s_pin && pin <= c->e_pin)
+                       break;
+               c++;
+       }
+
+       if (c >= e)
+               return -EINVAL;
+
+       /* Calculated bits as the overall offset the pin is located at,
+        * if c->fixed is held, that determines the all the pins in the
+        * range use the same field with the s_pin.
+        */
+       bits = c->fixed ? c->s_bit : c->s_bit + (pin - c->s_pin) * (c->x_bits);
+
+       /* Fill pfd from bits. For example 32-bit register applied is assumed
+        * when c->sz_reg is equal to 32.
+        */
+       pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg);
+       pfd->bitpos = bits % c->sz_reg;
+       pfd->mask = (1 << c->x_bits) - 1;
+
+       /* pfd->next is used for indicating that bit wrapping-around happens
+        * which requires the manipulation for bit 0 starting in the next
+        * register to form the complete field read/write.
+        */
+       pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0;
+
+       return 0;
+}
+
+static int mtk_hw_pin_field_get(struct udevice *dev, int pin,
+                               int field, struct mtk_pin_field *pfd)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct mtk_pin_reg_calc *rc;
+
+       if (field < 0 || field >= PINCTRL_PIN_REG_MAX)
+               return -EINVAL;
+
+       if (priv->soc->reg_cal && priv->soc->reg_cal[field].range)
+               rc = &priv->soc->reg_cal[field];
+       else
+               return -EINVAL;
+
+       return mtk_hw_pin_field_lookup(dev, pin, rc, pfd);
+}
+
+static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
+{
+       *l = 32 - pf->bitpos;
+       *h = get_count_order(pf->mask) - *l;
+}
+
+static void mtk_hw_write_cross_field(struct udevice *dev,
+                                    struct mtk_pin_field *pf, int value)
+{
+       int nbits_l, nbits_h;
+
+       mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+       mtk_rmw(dev, pf->offset, pf->mask << pf->bitpos,
+               (value & pf->mask) << pf->bitpos);
+
+       mtk_rmw(dev, pf->offset + pf->next, BIT(nbits_h) - 1,
+               (value & pf->mask) >> nbits_l);
+}
+
+static void mtk_hw_read_cross_field(struct udevice *dev,
+                                   struct mtk_pin_field *pf, int *value)
+{
+       int nbits_l, nbits_h, h, l;
+
+       mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+       l  = (mtk_r32(dev, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
+       h  = (mtk_r32(dev, pf->offset + pf->next)) & (BIT(nbits_h) - 1);
+
+       *value = (h << nbits_l) | l;
+}
+
+static int mtk_hw_set_value(struct udevice *dev, int pin, int field,
+                           int value)
+{
+       struct mtk_pin_field pf;
+       int err;
+
+       err = mtk_hw_pin_field_get(dev, pin, field, &pf);
+       if (err)
+               return err;
+
+       if (!pf.next)
+               mtk_rmw(dev, pf.offset, pf.mask << pf.bitpos,
+                       (value & pf.mask) << pf.bitpos);
+       else
+               mtk_hw_write_cross_field(dev, &pf, value);
+
+       return 0;
+}
+
+static int mtk_hw_get_value(struct udevice *dev, int pin, int field,
+                           int *value)
+{
+       struct mtk_pin_field pf;
+       int err;
+
+       err = mtk_hw_pin_field_get(dev, pin, field, &pf);
+       if (err)
+               return err;
+
+       if (!pf.next)
+               *value = (mtk_r32(dev, pf.offset) >> pf.bitpos) & pf.mask;
+       else
+               mtk_hw_read_cross_field(dev, &pf, value);
+
+       return 0;
+}
+
+static int mtk_get_groups_count(struct udevice *dev)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->soc->ngrps;
+}
+
+static const char *mtk_get_pin_name(struct udevice *dev,
+                                   unsigned int selector)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       if (!priv->soc->grps[selector].name)
+               return mtk_pinctrl_dummy_name;
+
+       return priv->soc->pins[selector].name;
+}
+
+static int mtk_get_pins_count(struct udevice *dev)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->soc->npins;
+}
+
+static const char *mtk_get_group_name(struct udevice *dev,
+                                     unsigned int selector)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       if (!priv->soc->grps[selector].name)
+               return mtk_pinctrl_dummy_name;
+
+       return priv->soc->grps[selector].name;
+}
+
+static int mtk_get_functions_count(struct udevice *dev)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->soc->nfuncs;
+}
+
+static const char *mtk_get_function_name(struct udevice *dev,
+                                        unsigned int selector)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+       if (!priv->soc->funcs[selector].name)
+               return mtk_pinctrl_dummy_name;
+
+       return priv->soc->funcs[selector].name;
+}
+
+static int mtk_pinmux_group_set(struct udevice *dev,
+                               unsigned int group_selector,
+                               unsigned int func_selector)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct mtk_group_desc *grp =
+                       &priv->soc->grps[group_selector];
+       int i;
+
+       for (i = 0; i < grp->num_pins; i++) {
+               int *pin_modes = grp->data;
+
+               mtk_hw_set_value(dev, grp->pins[i], PINCTRL_PIN_REG_MODE,
+                                pin_modes[i]);
+       }
+
+       return 0;
+}
+
+#if CONFIG_IS_ENABLED(PINCONF)
+static const struct pinconf_param mtk_conf_params[] = {
+       { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+       { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+       { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+       { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+       { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+       { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+       { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+       { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+       { "output-high", PIN_CONFIG_OUTPUT, 1, },
+       { "output-low", PIN_CONFIG_OUTPUT, 0, },
+       { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+};
+
+int mtk_pinconf_drive_set(struct udevice *dev, u32 pin, u32 arg)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct mtk_pin_desc *desc = &priv->soc->pins[pin];
+       const struct mtk_drive_desc *tb;
+       int err = -ENOTSUPP;
+
+       tb = &mtk_drive[desc->drv_n];
+       /* 4mA when (e8, e4) = (0, 0)
+        * 8mA when (e8, e4) = (0, 1)
+        * 12mA when (e8, e4) = (1, 0)
+        * 16mA when (e8, e4) = (1, 1)
+        */
+       if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
+               arg = (arg / tb->step - 1) * tb->scal;
+
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DRV, arg);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int mtk_pinconf_set(struct udevice *dev, unsigned int pin,
+                          unsigned int param, unsigned int arg)
+{
+       int err = 0;
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+       case PIN_CONFIG_BIAS_PULL_UP:
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
+                       (param == PIN_CONFIG_BIAS_PULL_UP) ? 3 : 2;
+
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLSEL,
+                                      arg & 1);
+               if (err)
+                       goto err;
+
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLEN,
+                                      !!(arg & 2));
+               if (err)
+                       goto err;
+               break;
+       case PIN_CONFIG_OUTPUT_ENABLE:
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT, 0);
+               if (err)
+                       goto err;
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
+               if (err)
+                       goto err;
+               break;
+       case PIN_CONFIG_INPUT_ENABLE:
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_IES, 1);
+               if (err)
+                       goto err;
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 0);
+               if (err)
+                       goto err;
+               break;
+       case PIN_CONFIG_OUTPUT:
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
+               if (err)
+                       goto err;
+
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DO, arg);
+               if (err)
+                       goto err;
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               /* arg = 1: Input mode & SMT enable ;
+                * arg = 0: Output mode & SMT disable
+                */
+               arg = arg ? 2 : 1;
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR,
+                                      arg & 1);
+               if (err)
+                       goto err;
+
+               err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT,
+                                      !!(arg & 2));
+               if (err)
+                       goto err;
+               break;
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               err = mtk_pinconf_drive_set(dev, pin, arg);
+               if (err)
+                       goto err;
+               break;
+
+       default:
+               err = -ENOTSUPP;
+       }
+
+err:
+
+       return err;
+}
+
+static int mtk_pinconf_group_set(struct udevice *dev,
+                                unsigned int group_selector,
+                                unsigned int param, unsigned int arg)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct mtk_group_desc *grp =
+                       &priv->soc->grps[group_selector];
+       int i, ret;
+
+       for (i = 0; i < grp->num_pins; i++) {
+               ret = mtk_pinconf_set(dev, grp->pins[i], param, arg);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif
+
+const struct pinctrl_ops mtk_pinctrl_ops = {
+       .get_pins_count = mtk_get_pins_count,
+       .get_pin_name = mtk_get_pin_name,
+       .get_groups_count = mtk_get_groups_count,
+       .get_group_name = mtk_get_group_name,
+       .get_functions_count = mtk_get_functions_count,
+       .get_function_name = mtk_get_function_name,
+       .pinmux_group_set = mtk_pinmux_group_set,
+#if CONFIG_IS_ENABLED(PINCONF)
+       .pinconf_num_params = ARRAY_SIZE(mtk_conf_params),
+       .pinconf_params = mtk_conf_params,
+       .pinconf_set = mtk_pinconf_set,
+       .pinconf_group_set = mtk_pinconf_group_set,
+#endif
+       .set_state = pinctrl_generic_set_state,
+};
+
+static int mtk_gpio_get(struct udevice *dev, unsigned int off)
+{
+       int val, err;
+
+       err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DI, &val);
+       if (err)
+               return err;
+
+       return !!val;
+}
+
+static int mtk_gpio_set(struct udevice *dev, unsigned int off, int val)
+{
+       return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DO, !!val);
+}
+
+static int mtk_gpio_get_direction(struct udevice *dev, unsigned int off)
+{
+       int val, err;
+
+       err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DIR, &val);
+       if (err)
+               return err;
+
+       return val ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static int mtk_gpio_direction_input(struct udevice *dev, unsigned int off)
+{
+       return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 0);
+}
+
+static int mtk_gpio_direction_output(struct udevice *dev,
+                                    unsigned int off, int val)
+{
+       mtk_gpio_set(dev, off, val);
+
+       /* And set the requested value */
+       return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 1);
+}
+
+static int mtk_gpio_request(struct udevice *dev, unsigned int off,
+                           const char *label)
+{
+       return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_MODE, 0);
+}
+
+static int mtk_gpio_probe(struct udevice *dev)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev->parent);
+       struct gpio_dev_priv *uc_priv;
+
+       uc_priv = dev_get_uclass_priv(dev);
+       uc_priv->bank_name = priv->soc->name;
+       uc_priv->gpio_count = priv->soc->npins;
+
+       return 0;
+}
+
+static const struct dm_gpio_ops mtk_gpio_ops = {
+       .request = mtk_gpio_request,
+       .set_value = mtk_gpio_set,
+       .get_value = mtk_gpio_get,
+       .get_function = mtk_gpio_get_direction,
+       .direction_input = mtk_gpio_direction_input,
+       .direction_output = mtk_gpio_direction_output,
+};
+
+static struct driver mtk_gpio_driver = {
+       .name = "mediatek_gpio",
+       .id     = UCLASS_GPIO,
+       .probe = mtk_gpio_probe,
+       .ops = &mtk_gpio_ops,
+};
+
+static int mtk_gpiochip_register(struct udevice *parent)
+{
+       struct uclass_driver *drv;
+       struct udevice *dev;
+       int ret;
+       ofnode node;
+
+       drv = lists_uclass_lookup(UCLASS_GPIO);
+       if (!drv)
+               return -ENOENT;
+
+       dev_for_each_subnode(node, parent)
+               if (ofnode_read_bool(node, "gpio-controller")) {
+                       ret = 0;
+                       break;
+               }
+
+       if (ret)
+               return ret;
+
+       ret = device_bind_with_driver_data(parent, &mtk_gpio_driver,
+                                          "mediatek_gpio", 0, node,
+                                          &dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int mtk_pinctrl_common_probe(struct udevice *dev,
+                            struct mtk_pinctrl_soc *soc)
+{
+       struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       priv->base = dev_read_addr_ptr(dev);
+       if (priv->base == (void *)FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       priv->soc = soc;
+
+       ret = mtk_gpiochip_register(dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
new file mode 100644 (file)
index 0000000..69af5a7
--- /dev/null
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#ifndef __PINCTRL_MEDIATEK_H__
+#define __PINCTRL_MEDIATEK_H__
+
+#define MTK_RANGE(_a)          { .range = (_a), .nranges = ARRAY_SIZE(_a), }
+#define MTK_PIN(_number, _name, _drv_n) {                              \
+               .number = _number,                                      \
+               .name = _name,                                          \
+               .drv_n = _drv_n,                                        \
+       }
+
+#define PINCTRL_PIN_GROUP(name, id)                                    \
+       {                                                               \
+               name,                                                   \
+               id##_pins,                                              \
+               ARRAY_SIZE(id##_pins),                                  \
+               id##_funcs,                                             \
+       }
+
+#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,      \
+                       _x_bits, _sz_reg, _fixed) {                     \
+               .s_pin = _s_pin,                                        \
+               .e_pin = _e_pin,                                        \
+               .s_addr = _s_addr,                                      \
+               .x_addrs = _x_addrs,                                    \
+               .s_bit = _s_bit,                                        \
+               .x_bits = _x_bits,                                      \
+               .sz_reg = _sz_reg,                                      \
+               .fixed = _fixed,                                        \
+       }
+
+/* List these attributes which could be modified for the pin */
+enum {
+       PINCTRL_PIN_REG_MODE,
+       PINCTRL_PIN_REG_DIR,
+       PINCTRL_PIN_REG_DI,
+       PINCTRL_PIN_REG_DO,
+       PINCTRL_PIN_REG_IES,
+       PINCTRL_PIN_REG_SMT,
+       PINCTRL_PIN_REG_PULLEN,
+       PINCTRL_PIN_REG_PULLSEL,
+       PINCTRL_PIN_REG_DRV,
+       PINCTRL_PIN_REG_MAX,
+};
+
+/* Group the pins by the driving current */
+enum {
+       DRV_FIXED,
+       DRV_GRP0,
+       DRV_GRP1,
+       DRV_GRP2,
+       DRV_GRP3,
+       DRV_GRP4,
+};
+
+/**
+ * struct mtk_pin_field - the structure that holds the information of the field
+ *                       used to describe the attribute for the pin
+ * @offset:            the register offset relative to the base address
+ * @mask:              the mask used to filter out the field from the register
+ * @bitpos:            the start bit relative to the register
+ * @next:              the indication that the field would be extended to the
+                       next register
+ */
+struct mtk_pin_field {
+       u32 offset;
+       u32 mask;
+       u8 bitpos;
+       u8 next;
+};
+
+/**
+ * struct mtk_pin_field_calc - the structure that holds the range providing
+ *                            the guide used to look up the relevant field
+ * @s_pin:             the start pin within the range
+ * @e_pin:             the end pin within the range
+ * @s_addr:            the start address for the range
+ * @x_addrs:           the address distance between two consecutive registers
+ *                     within the range
+ * @s_bit:             the start bit for the first register within the range
+ * @x_bits:            the bit distance between two consecutive pins within
+ *                     the range
+ * @sz_reg:            the size of bits in a register
+ * @fixed:             the consecutive pins share the same bits with the 1st
+ *                     pin
+ */
+struct mtk_pin_field_calc {
+       u16 s_pin;
+       u16 e_pin;
+       u32 s_addr;
+       u8 x_addrs;
+       u8 s_bit;
+       u8 x_bits;
+       u8 sz_reg;
+       u8 fixed;
+};
+
+/**
+ * struct mtk_pin_reg_calc - the structure that holds all ranges used to
+ *                          determine which register the pin would make use of
+ *                          for certain pin attribute.
+ * @range:                  the start address for the range
+ * @nranges:                the number of items in the range
+ */
+struct mtk_pin_reg_calc {
+       const struct mtk_pin_field_calc *range;
+       unsigned int nranges;
+};
+
+/**
+ * struct mtk_pin_desc - the structure that providing information
+ *                      for each pin of chips
+ * @number:            unique pin number from the global pin number space
+ * @name:              name for this pin
+ * @drv_n:             the index with the driving group
+ */
+struct mtk_pin_desc {
+       unsigned int number;
+       const char *name;
+       u8 drv_n;
+};
+
+/**
+ * struct mtk_group_desc - generic pin group descriptor
+ * @name: name of the pin group
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @data: pin controller driver specific data
+ */
+struct mtk_group_desc {
+       const char *name;
+       int *pins;
+       int num_pins;
+       void *data;
+};
+
+/**
+ * struct mtk_function_desc - generic function descriptor
+ * @name: name of the function
+ * @group_names: array of pin group names
+ * @num_group_names: number of pin group names
+ */
+struct mtk_function_desc {
+       const char *name;
+       const char * const *group_names;
+       int num_group_names;
+};
+
+/* struct mtk_pin_soc - the structure that holds SoC-specific data */
+struct mtk_pinctrl_soc {
+       const char *name;
+       const struct mtk_pin_reg_calc *reg_cal;
+       const struct mtk_pin_desc *pins;
+       int npins;
+       const struct mtk_group_desc *grps;
+       int ngrps;
+       const struct mtk_function_desc *funcs;
+       int nfuncs;
+};
+
+/**
+ * struct mtk_pinctrl_priv - private data for MTK pinctrl driver
+ *
+ * @base: base address of the pinctrl device
+ * @soc: SoC specific data
+ */
+struct mtk_pinctrl_priv {
+       void __iomem *base;
+       struct mtk_pinctrl_soc *soc;
+};
+
+extern const struct pinctrl_ops mtk_pinctrl_ops;
+
+int mtk_pinctrl_common_probe(struct udevice *dev,
+                            struct mtk_pinctrl_soc *soc);
+
+#endif /* __PINCTRL_MEDIATEK_H__ */