pinctrl: qcom: make compatible with linux DTs

The pinctrl and GPIO drivers are currently heavily incompatible with
upstream. Most Qualcomm pinctrl blocks feature "tiles" of pins, each at
it's own address. Introduce support for these by allowing the soc driver
to specify per-pin register offsets similarly to the Linux driver.

Adjust the GPIO driver to handle these too, and finally enable support
for all pins with the same numbering as used in Linux.

Reviewed-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
diff --git a/arch/arm/dts/dragonboard845c-uboot.dtsi b/arch/arm/dts/dragonboard845c-uboot.dtsi
index 7106db8..7728f4f 100644
--- a/arch/arm/dts/dragonboard845c-uboot.dtsi
+++ b/arch/arm/dts/dragonboard845c-uboot.dtsi
@@ -19,7 +19,7 @@
 			bootph-all;
 		};
 
-		pinctrl_north@3900000 {
+		pinctrl@3400000 {
 			bootph-all;
 		};
 	};
diff --git a/arch/arm/dts/sdm845.dtsi b/arch/arm/dts/sdm845.dtsi
index 3b86b93..4798ace 100644
--- a/arch/arm/dts/sdm845.dtsi
+++ b/arch/arm/dts/sdm845.dtsi
@@ -26,23 +26,13 @@
 			#power-domain-cells = <1>;
 		};
 
-		gpio_north: gpio_north@3900000 {
-			#gpio-cells = <2>;
+		tlmm: pinctrl@3400000 {
 			compatible = "qcom,sdm845-pinctrl";
-			reg = <0x3900000 0x400000>;
-			gpio-count = <150>;
-			gpio-controller;
-			gpio-ranges = <&gpio_north 0 0 150>;
-			gpio-bank-name = "soc_north.";
-		};
-
-		tlmm_north: pinctrl_north@3900000 {
-			compatible = "qcom,sdm845-pinctrl";
-			reg = <0x3900000 0x400000>;
+			reg = <0x3400000 0xc00000>;
 			gpio-count = <150>;
 			gpio-controller;
 			#gpio-cells = <2>;
-			gpio-ranges = <&tlmm_north 0 0 150>;
+			gpio-ranges = <&tlmm 0 0 150>;
 
 			/* DEBUG UART */
 			qup_uart9: qup-uart9-default {
diff --git a/arch/arm/dts/starqltechn-uboot.dtsi b/arch/arm/dts/starqltechn-uboot.dtsi
index d81a22f..034d5c1 100644
--- a/arch/arm/dts/starqltechn-uboot.dtsi
+++ b/arch/arm/dts/starqltechn-uboot.dtsi
@@ -19,10 +19,7 @@
 		clock-controller@100000 {
 			bootph-all;
 		};
-		gpio_north@3900000 {
-			bootph-all;
-		};
-		pinctrl_north@3900000 {
+		pinctrl@3400000 {
 			bootph-all;
 		};
 	};
diff --git a/arch/arm/dts/starqltechn.dts b/arch/arm/dts/starqltechn.dts
index eec51d1..5b6372b 100644
--- a/arch/arm/dts/starqltechn.dts
+++ b/arch/arm/dts/starqltechn.dts
@@ -65,15 +65,15 @@
 		serial@a84000 {
 			status = "okay";
 		};
+	};
+};
 
-		pinctrl_north@3900000 {
-			muic_i2c: muic_i2c {
-				pins = "GPIO_33", "GPIO_34";
-				drive-strength = <0x2>;
-				function = "gpio";
-				bias-disable;
-			};
-		};
+&tlmm {
+	muic_i2c: muic-i2c-n {
+		pins = "GPIO_33", "GPIO_34";
+		drive-strength = <0x2>;
+		function = "gpio";
+		bias-disable;
 	};
 };
 
diff --git a/arch/arm/mach-snapdragon/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h
index bbc2bc1..8dac62f 100644
--- a/arch/arm/mach-snapdragon/include/mach/gpio.h
+++ b/arch/arm/mach-snapdragon/include/mach/gpio.h
@@ -1,8 +1,28 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Empty gpio.h
+ * Qualcomm common pin control data.
  *
- * This file must stay as arch/arm/include/asm/gpio.h requires it.
- *
- * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ * Copyright (C) 2023 Linaro Ltd.
  */
+#ifndef _QCOM_GPIO_H_
+#define _QCOM_GPIO_H_
+
+#include <asm/types.h>
+#include <stdbool.h>
+
+struct msm_pin_data {
+	int pin_count;
+	const unsigned int *pin_offsets;
+};
+
+static inline u32 qcom_pin_offset(const unsigned int *offs, unsigned int selector)
+{
+	u32 out = (selector * 0x1000);
+
+	if (offs)
+		return out + offs[selector];
+
+	return out;
+}
+
+#endif /* _QCOM_GPIO_H_ */
diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c
index 51670f2..d9355ed 100644
--- a/drivers/gpio/msm_gpio.c
+++ b/drivers/gpio/msm_gpio.c
@@ -11,13 +11,10 @@
 #include <asm/global_data.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
+#include <mach/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Register offsets */
-#define GPIO_CONFIG_OFF(no)         ((no) * 0x1000)
-#define GPIO_IN_OUT_OFF(no)         ((no) * 0x1000 + 0x4)
-
 /* OE */
 #define GPIO_OE_DISABLE  (0x0 << 9)
 #define GPIO_OE_ENABLE   (0x1 << 9)
@@ -29,15 +26,22 @@
 
 struct msm_gpio_bank {
 	phys_addr_t base;
+	const struct msm_pin_data *pin_data;
 };
 
+#define GPIO_CONFIG_REG(dev, x) \
+	(qcom_pin_offset(((struct msm_gpio_bank *)dev_get_priv(dev))->pin_data->pin_offsets, x))
+
+#define GPIO_IN_OUT_REG(dev, x) \
+	(GPIO_CONFIG_REG(dev, x) + 0x4)
+
 static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio)
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
-	phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
 
 	/* Disable OE bit */
-	clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_DISABLE);
+	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
+			GPIO_OE_MASK, GPIO_OE_DISABLE);
 
 	return 0;
 }
@@ -48,7 +52,7 @@
 
 	value = !!value;
 	/* set value */
-	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
 
 	return 0;
 }
@@ -57,13 +61,13 @@
 				     int value)
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
-	phys_addr_t reg = priv->base + GPIO_CONFIG_OFF(gpio);
 
 	value = !!value;
 	/* set value */
-	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_OFF(gpio));
+	writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio));
 	/* switch direction */
-	clrsetbits_le32(reg, GPIO_OE_MASK, GPIO_OE_ENABLE);
+	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio),
+			GPIO_OE_MASK, GPIO_OE_ENABLE);
 
 	return 0;
 }
@@ -72,14 +76,14 @@
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
-	return !!(readl(priv->base + GPIO_IN_OUT_OFF(gpio)) >> GPIO_IN);
+	return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN);
 }
 
-static int msm_gpio_get_function(struct udevice *dev, unsigned offset)
+static int msm_gpio_get_function(struct udevice *dev, unsigned gpio)
 {
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
-	if (readl(priv->base + GPIO_CONFIG_OFF(offset)) & GPIO_OE_ENABLE)
+	if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE)
 		return GPIOF_OUTPUT;
 
 	return GPIOF_INPUT;
@@ -98,6 +102,7 @@
 	struct msm_gpio_bank *priv = dev_get_priv(dev);
 
 	priv->base = dev_read_addr(dev);
+	priv->pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
 
 	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
 }
@@ -105,9 +110,10 @@
 static int msm_gpio_of_to_plat(struct udevice *dev)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	const struct msm_pin_data *pin_data = (struct msm_pin_data *)dev_get_driver_data(dev);
 
-	uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
-					     "gpio-count", 0);
+	/* Get the pin count from the pinctrl driver */
+	uc_priv->gpio_count = pin_data->pin_count;
 	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
 					 "gpio-bank-name", NULL);
 	if (uc_priv->bank_name == NULL)
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
index bcbc0df..8149ffd 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8016.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -55,7 +55,7 @@
 }
 
 static const struct msm_pinctrl_data apq8016_data = {
-	.pin_count = 133,
+	.pin_data = { .pin_count = 133, },
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = apq8016_get_function_name,
 	.get_function_mux = apq8016_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
index 5250856..d64ab1f 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8096.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -50,7 +50,7 @@
 }
 
 static const struct msm_pinctrl_data apq8096_data = {
-	.pin_count = 157,
+	.pin_data = { .pin_count = 157, },
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = apq8096_get_function_name,
 	.get_function_mux = apq8096_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index 87058e2..2d99f99 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -46,7 +46,7 @@
 }
 
 static const struct msm_pinctrl_data ipq4019_data = {
-	.pin_count = 100,
+	.pin_data = { .pin_count = 100, },
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = ipq4019_get_function_name,
 	.get_function_mux = ipq4019_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 1cface7..dc3d8c4 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -13,8 +13,11 @@
 #include <dm/device_compat.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <asm/gpio.h>
 #include <dm/pinctrl.h>
 #include <linux/bitops.h>
+#include <mach/gpio.h>
+
 #include "pinctrl-qcom.h"
 
 struct msm_pinctrl_priv {
@@ -22,7 +25,9 @@
 	struct msm_pinctrl_data *data;
 };
 
-#define GPIO_CONFIG_OFFSET(x)         ((x) * 0x1000)
+#define GPIO_CONFIG_REG(priv, x) \
+	(qcom_pin_offset((priv)->data->pin_data.pin_offsets, x))
+
 #define TLMM_GPIO_PULL_MASK GENMASK(1, 0)
 #define TLMM_FUNC_SEL_MASK GENMASK(5, 2)
 #define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6)
@@ -45,7 +50,7 @@
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
-	return priv->data->pin_count;
+	return priv->data->pin_data.pin_count;
 }
 
 static const char *msm_get_function_name(struct udevice *dev,
@@ -61,7 +66,7 @@
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
 	priv->base = dev_read_addr(dev);
-	priv->data = (struct msm_pinctrl_data *)dev->driver_data;
+	priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
 
 	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
 }
@@ -78,7 +83,7 @@
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
-	clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
 			TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
 			priv->data->get_function_mux(func_selector) << 2);
 	return 0;
@@ -92,15 +97,15 @@
 	switch (param) {
 	case PIN_CONFIG_DRIVE_STRENGTH:
 		argument = (argument / 2) - 1;
-		clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+		clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
 				TLMM_DRV_STRENGTH_MASK, argument << 6);
 		break;
 	case PIN_CONFIG_BIAS_DISABLE:
-		clrbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+		clrbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
 			     TLMM_GPIO_PULL_MASK);
 		break;
 	case PIN_CONFIG_BIAS_PULL_UP:
-		clrsetbits_le32(priv->base + GPIO_CONFIG_OFFSET(pin_selector),
+		clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
 				TLMM_GPIO_PULL_MASK, argument);
 		break;
 	default:
@@ -149,9 +154,15 @@
 	if (!name)
 		return -EINVAL;
 
-	/* Bind gpio node */
-	ret = device_bind_driver_to_node(dev, "gpio_msm",
-					 name, node, NULL);
+	drv = lists_driver_lookup_name("gpio_msm");
+	if (!drv) {
+		printf("Can't find gpio_msm driver\n");
+		return -ENODEV;
+	}
+
+	/* Bind gpio device as a child of the pinctrl device */
+	ret = device_bind_with_driver_data(pinctrl_dev, drv,
+					   name, (ulong)&data->pin_data, node, NULL);
 	if (ret) {
 		device_unbind(pinctrl_dev);
 		return ret;
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.h b/drivers/pinctrl/qcom/pinctrl-qcom.h
index 1edd9a4..07f2eae 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.h
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.h
@@ -8,10 +8,13 @@
 #ifndef _PINCTRL_QCOM_H
 #define _PINCTRL_QCOM_H
 
+#include <asm/types.h>
+#include <mach/gpio.h>
+
 struct udevice;
 
 struct msm_pinctrl_data {
-	int pin_count;
+	struct msm_pin_data pin_data;
 	int functions_count;
 	const char *(*get_function_name)(struct udevice *dev,
 					 unsigned int selector);
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
index 272331c..ac00afa 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -62,7 +62,7 @@
 }
 
 static struct msm_pinctrl_data qcs404_data = {
-	.pin_count = 126,
+	.pin_data = { .pin_count = 126, },
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = qcs404_get_function_name,
 	.get_function_mux = qcs404_get_function_mux,
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 1a09c5c..9f0f408 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -3,6 +3,7 @@
  * Qualcomm SDM845 pinctrl
  *
  * (C) Copyright 2021 Dzmitry Sankouski <dsankouski@gmail.com>
+ * (C) Copyright 2023 Linaro Ltd.
  *
  */
 
@@ -11,6 +12,10 @@
 
 #include "pinctrl-qcom.h"
 
+#define NORTH	0x00500000
+#define SOUTH	0x00900000
+#define EAST	0x00100000
+
 #define MAX_PIN_NAME_LEN 32
 static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
 
@@ -19,6 +24,39 @@
 	{"gpio", 0},
 };
 
+static const unsigned int sdm845_pin_offsets[] = {
+	[0] = EAST,    [1] = EAST,    [2] = EAST,    [3] = EAST,    [4] = NORTH,
+	[5] = NORTH,   [6] = NORTH,   [7] = NORTH,   [8] = EAST,    [9] = EAST,
+	[10] = EAST,   [11] = EAST,   [12] = SOUTH,  [13] = SOUTH,  [14] = SOUTH,
+	[15] = SOUTH,  [16] = SOUTH,  [17] = SOUTH,  [18] = SOUTH,  [19] = SOUTH,
+	[20] = SOUTH,  [21] = SOUTH,  [22] = SOUTH,  [23] = SOUTH,  [24] = SOUTH,
+	[25] = SOUTH,  [26] = SOUTH,  [27] = EAST,   [28] = EAST,   [29] = EAST,
+	[30] = EAST,   [31] = NORTH,  [32] = NORTH,  [33] = NORTH,  [34] = NORTH,
+	[35] = SOUTH,  [36] = SOUTH,  [37] = SOUTH,  [38] = NORTH,  [39] = EAST,
+	[40] = SOUTH,  [41] = EAST,   [42] = EAST,   [43] = EAST,   [44] = EAST,
+	[45] = EAST,   [46] = EAST,   [47] = EAST,   [48] = EAST,   [49] = NORTH,
+	[50] = NORTH,  [51] = NORTH,  [52] = NORTH,  [53] = NORTH,  [54] = NORTH,
+	[55] = NORTH,  [56] = NORTH,  [57] = NORTH,  [58] = NORTH,  [59] = NORTH,
+	[60] = NORTH,  [61] = NORTH,  [62] = NORTH,  [63] = NORTH,  [64] = NORTH,
+	[65] = NORTH,  [66] = NORTH,  [67] = NORTH,  [68] = NORTH,  [69] = EAST,
+	[70] = EAST,   [71] = EAST,   [72] = EAST,   [73] = EAST,   [74] = EAST,
+	[75] = EAST,   [76] = EAST,   [77] = EAST,   [78] = EAST,   [79] = NORTH,
+	[80] = NORTH,  [81] = NORTH,  [82] = NORTH,  [83] = NORTH,  [84] = NORTH,
+	[85] = EAST,   [86] = EAST,   [87] = EAST,   [88] = EAST,   [89] = SOUTH,
+	[90] = SOUTH,  [91] = SOUTH,  [92] = SOUTH,  [93] = SOUTH,  [94] = SOUTH,
+	[95] = SOUTH,  [96] = SOUTH,  [97] = NORTH,  [98] = NORTH,  [99] = NORTH,
+	[100] = NORTH, [101] = NORTH, [102] = NORTH, [103] = NORTH, [104] = NORTH,
+	[105] = NORTH, [106] = NORTH, [107] = NORTH, [108] = NORTH, [109] = NORTH,
+	[110] = NORTH, [111] = NORTH, [112] = NORTH, [113] = NORTH, [114] = NORTH,
+	[115] = NORTH, [116] = NORTH, [117] = NORTH, [118] = NORTH, [119] = NORTH,
+	[120] = NORTH, [121] = NORTH, [122] = EAST,  [123] = EAST,  [124] = EAST,
+	[125] = EAST,  [126] = EAST,  [127] = NORTH, [128] = NORTH, [129] = NORTH,
+	[130] = NORTH, [131] = NORTH, [132] = NORTH, [133] = NORTH, [134] = NORTH,
+	[135] = NORTH, [136] = NORTH, [137] = NORTH, [138] = NORTH, [139] = NORTH,
+	[140] = NORTH, [141] = NORTH, [142] = NORTH, [143] = NORTH, [144] = NORTH,
+	[145] = NORTH, [146] = NORTH, [147] = NORTH, [148] = NORTH, [149] = NORTH,
+};
+
 static const char *sdm845_get_function_name(struct udevice *dev,
 					     unsigned int selector)
 {
@@ -28,7 +66,7 @@
 static const char *sdm845_get_pin_name(struct udevice *dev,
 					unsigned int selector)
 {
-	snprintf(pin_name, MAX_PIN_NAME_LEN, "GPIO_%u", selector);
+	snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 	return pin_name;
 }
 
@@ -38,7 +76,10 @@
 }
 
 static struct msm_pinctrl_data sdm845_data = {
-	.pin_count = 150,
+	.pin_data = {
+		.pin_offsets = sdm845_pin_offsets,
+		.pin_count = ARRAY_SIZE(sdm845_pin_offsets),
+	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = sdm845_get_function_name,
 	.get_function_mux = sdm845_get_function_mux,