linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT
@ 2020-11-16 12:59 Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
                   ` (7 more replies)
  0 siblings, 8 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Colin Ian King, Dan Carpenter,
	Greg Kroah-Hartman, Kishon Vijay Abraham I, Krzysztof Kozlowski,
	Lee Jones, Liam Girdwood, Mark Brown, Mayulong, Rob Herring,
	Stephen Boyd, Vinod Koul, Wei Xu, Yu Chen, YueHaibing, devel,
	devicetree, linux-arm-kernel, linux-arm-msm, linux-kernel

This patch series finish addressing support for Hikey 970
USB.

It moves the power management and USB3 drivers out of
staging, adding the device tree changes required for USB3
to work on Hikey 970.

Mauro Carvalho Chehab (8):
  phy: phy-hi3670-usb3: move driver from staging into phy
  spmi: hi6421-spmi-pmic: move driver from staging
  mfd: hi6421-spmi-pmic: move driver from staging
  regulator: hi6421v600-regulator: move it from staging
  arm64: dts: hisilicon: hi3670.dtsi: add I2C settings
  arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings
  dts: hisilicon: add support for USB3 on Hikey 970
  dts: hisilicon: add support for the PMIC found on Hikey 970

 .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 159 +++++
 .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
 .../spmi/hisilicon,hisi-spmi-controller.yaml  |  62 ++
 MAINTAINERS                                   |  24 +-
 .../boot/dts/hisilicon/hi3670-hikey970.dts    | 124 +++-
 arch/arm64/boot/dts/hisilicon/hi3670.dtsi     | 135 ++++
 .../boot/dts/hisilicon/hikey970-pinctrl.dtsi  | 548 +++++++++++++-
 .../boot/dts/hisilicon/hikey970-pmic.dtsi     | 197 +++++
 drivers/mfd/Kconfig                           |  15 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/hi6421-spmi-pmic.c                | 342 +++++++++
 drivers/phy/hisilicon/Kconfig                 |  10 +
 drivers/phy/hisilicon/Makefile                |   1 +
 drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
 drivers/regulator/Kconfig                     |   9 +
 drivers/regulator/Makefile                    |   1 +
 drivers/regulator/hi6421v600-regulator.c      | 478 +++++++++++++
 drivers/spmi/Kconfig                          |   9 +
 drivers/spmi/Makefile                         |   1 +
 drivers/spmi/hisi-spmi-controller.c           | 358 ++++++++++
 drivers/staging/Kconfig                       |   2 -
 drivers/staging/Makefile                      |   1 -
 drivers/staging/hikey9xx/Kconfig              |  49 --
 drivers/staging/hikey9xx/Makefile             |   7 -
 drivers/staging/hikey9xx/TODO                 |   5 -
 drivers/staging/hikey9xx/hi6421-spmi-pmic.c   | 342 ---------
 .../staging/hikey9xx/hi6421v600-regulator.c   | 478 -------------
 .../staging/hikey9xx/hisi-spmi-controller.c   | 358 ----------
 .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml  | 159 -----
 .../hisilicon,hisi-spmi-controller.yaml       |  62 --
 drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --
 32 files changed, 3183 insertions(+), 2240 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
 create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
 create mode 100644 arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
 create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
 create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c
 create mode 100644 drivers/regulator/hi6421v600-regulator.c
 create mode 100644 drivers/spmi/hisi-spmi-controller.c
 delete mode 100644 drivers/staging/hikey9xx/Kconfig
 delete mode 100644 drivers/staging/hikey9xx/Makefile
 delete mode 100644 drivers/staging/hikey9xx/TODO
 delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
 delete mode 100644 drivers/staging/hikey9xx/hi6421v600-regulator.c
 delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
 delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
 delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
 delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c
 delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml

-- 
2.28.0



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 15:31   ` Rob Herring
                     ` (2 more replies)
  2020-11-16 12:59 ` [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring, Vinod Koul
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Krzysztof Kozlowski, Yu Chen, devel,
	devicetree, linux-kernel

The phy USB3 driver for Hisilicon 970 (hi3670) is ready
for mainstream. Mode it from staging into the main driver's
phy/ directory.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
 MAINTAINERS                                   |   9 +-
 drivers/phy/hisilicon/Kconfig                 |  10 +
 drivers/phy/hisilicon/Makefile                |   1 +
 drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
 drivers/staging/hikey9xx/Kconfig              |  11 -
 drivers/staging/hikey9xx/Makefile             |   2 -
 drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --
 9 files changed, 762 insertions(+), 757 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
 create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c
 delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c
 delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml

diff --git a/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
new file mode 100644
index 000000000000..125a5d6546ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Hisilicon Kirin970 USB PHY
+
+maintainers:
+  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+description: |+
+  Bindings for USB3 PHY on HiSilicon Kirin 970.
+
+properties:
+  compatible:
+    const: hisilicon,hi3670-usb-phy
+
+  "#phy-cells":
+    const: 0
+
+  hisilicon,pericrg-syscon:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: phandle of syscon used to control iso refclk.
+
+  hisilicon,pctrl-syscon:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: phandle of syscon used to control usb tcxo.
+
+  hisilicon,sctrl-syscon:
+    $ref: '/schemas/types.yaml#/definitions/phandle'
+    description: phandle of syscon used to control phy deep sleep.
+
+  hisilicon,eye-diagram-param:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Eye diagram for phy.
+
+  hisilicon,tx-vboost-lvl:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: TX level vboost for phy.
+
+required:
+  - compatible
+  - hisilicon,pericrg-syscon
+  - hisilicon,pctrl-syscon
+  - hisilicon,sctrl-syscon
+  - hisilicon,eye-diagram-param
+  - hisilicon,tx-vboost-lvl
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    bus {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      usb3_otg_bc: usb3_otg_bc@ff200000 {
+        compatible = "syscon", "simple-mfd";
+        reg = <0x0 0xff200000 0x0 0x1000>;
+
+        usb_phy {
+          compatible = "hisilicon,hi3670-usb-phy";
+          #phy-cells = <0>;
+          hisilicon,pericrg-syscon = <&crg_ctrl>;
+          hisilicon,pctrl-syscon = <&pctrl>;
+          hisilicon,sctrl-syscon = <&sctrl>;
+          hisilicon,eye-diagram-param = <0xfdfee4>;
+          hisilicon,tx-vboost-lvl = <0x5>;
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index e451dcce054f..14266bb79ff8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18083,7 +18083,7 @@ L:	linux-usb@vger.kernel.org
 S:	Maintained
 F:	drivers/usb/roles/intel-xhci-usb-role-switch.c
 
-USB IP DRIVER FOR HISILICON KIRIN
+USB IP DRIVER FOR HISILICON KIRIN 960
 M:	Yu Chen <chenyu56@huawei.com>
 M:	Binghui Wang <wangbinghui@hisilicon.com>
 L:	linux-usb@vger.kernel.org
@@ -18091,6 +18091,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
 F:	drivers/phy/hisilicon/phy-hi3660-usb3.c
 
+USB IP DRIVER FOR HISILICON KIRIN 970
+M:	Mauro Carvalho Chehab <mchehab@kernel.org>
+L:	linux-usb@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/phy/hisilicon,kirin970-usb3.yaml
+F:	drivers/phy/hisilicon/phy-kirin970-usb3.c
+
 USB ISP116X DRIVER
 M:	Olav Kongas <ok@artecdesign.ee>
 L:	linux-usb@vger.kernel.org
diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig
index 1c73053bcc98..4d008cfc279c 100644
--- a/drivers/phy/hisilicon/Kconfig
+++ b/drivers/phy/hisilicon/Kconfig
@@ -23,6 +23,16 @@ config PHY_HI3660_USB
 
 	  To compile this driver as a module, choose M here.
 
+config PHY_HI3670_USB
+	tristate "hi3670 USB PHY support"
+	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
+	select GENERIC_PHY
+	select MFD_SYSCON
+	help
+	  Enable this to support the HISILICON HI3670 USB PHY.
+
+	  To compile this driver as a module, choose M here.
+
 config PHY_HISTB_COMBPHY
 	tristate "HiSilicon STB SoCs COMBPHY support"
 	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile
index 92e874ae9c74..51729868145b 100644
--- a/drivers/phy/hisilicon/Makefile
+++ b/drivers/phy/hisilicon/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_PHY_HI6220_USB)		+= phy-hi6220-usb.o
 obj-$(CONFIG_PHY_HI3660_USB)		+= phy-hi3660-usb3.o
+obj-$(CONFIG_PHY_HI3670_USB)		+= phy-hi3670-usb3.o
 obj-$(CONFIG_PHY_HISTB_COMBPHY)		+= phy-histb-combphy.o
 obj-$(CONFIG_PHY_HISI_INNO_USB2)	+= phy-hisi-inno-usb2.o
 obj-$(CONFIG_PHY_HIX5HD2_SATA)		+= phy-hix5hd2-sata.o
diff --git a/drivers/phy/hisilicon/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c
new file mode 100644
index 000000000000..4fc013911a78
--- /dev/null
+++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
+ *
+ * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
+ *		http://www.huawei.com
+ *
+ * Authors: Yu Chen <chenyu56@huawei.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define SCTRL_SCDEEPSLEEPED		(0x0)
+#define USB_CLK_SELECTED		BIT(20)
+
+#define PERI_CRG_PEREN0			(0x00)
+#define PERI_CRG_PERDIS0		(0x04)
+#define PERI_CRG_PEREN4			(0x40)
+#define PERI_CRG_PERDIS4		(0x44)
+#define PERI_CRG_PERRSTEN4		(0x90)
+#define PERI_CRG_PERRSTDIS4		(0x94)
+#define PERI_CRG_ISODIS			(0x148)
+#define PERI_CRG_PEREN6			(0x410)
+#define PERI_CRG_PERDIS6		(0x414)
+
+#define USB_REFCLK_ISO_EN		BIT(25)
+
+#define GT_CLK_USB2PHY_REF		BIT(19)
+
+#define PCTRL_PERI_CTRL3		(0x10)
+#define PCTRL_PERI_CTRL3_MSK_START	(16)
+#define USB_TCXO_EN			BIT(1)
+
+#define PCTRL_PERI_CTRL24		(0x64)
+#define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
+
+#define USB3OTG_CTRL0			(0x00)
+#define USB3OTG_CTRL3			(0x0C)
+#define USB3OTG_CTRL4			(0x10)
+#define USB3OTG_CTRL5			(0x14)
+#define USB3OTG_CTRL7			(0x1C)
+#define USB_MISC_CFG50			(0x50)
+#define USB_MISC_CFG54			(0x54)
+#define USB_MISC_CFG58			(0x58)
+#define USB_MISC_CFG5C			(0x5C)
+#define USB_MISC_CFGA0			(0xA0)
+#define TCA_CLK_RST			(0x200)
+#define TCA_INTR_EN			(0x204)
+#define TCA_INTR_STS			(0x208)
+#define TCA_GCFG			(0x210)
+#define TCA_TCPC			(0x214)
+#define TCA_SYSMODE_CFG			(0x218)
+#define TCA_VBUS_CTRL			(0x240)
+
+#define CTRL0_USB3_VBUSVLD		BIT(7)
+#define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
+
+#define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
+#define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
+
+#define CTRL5_USB2_SIDDQ		BIT(0)
+
+#define CTRL7_USB2_REFCLKSEL_MASK	(3 << 3)
+#define CTRL7_USB2_REFCLKSEL_ABB	(3 << 3)
+#define CTRL7_USB2_REFCLKSEL_PAD	(2 << 3)
+
+#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
+
+#define CFG54_USB31PHY_CR_ADDR_MASK	(0xFFFF)
+#define CFG54_USB31PHY_CR_ADDR_SHIFT	(16)
+#define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
+#define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
+#define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
+#define CFG54_USB31PHY_CR_ACK		BIT(7)
+#define CFG54_USB31PHY_CR_WR_EN		BIT(5)
+#define CFG54_USB31PHY_CR_SEL		BIT(4)
+#define CFG54_USB31PHY_CR_RD_EN		BIT(3)
+#define CFG54_USB31PHY_CR_CLK		BIT(2)
+#define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
+
+#define CFG58_USB31PHY_CR_DATA_MASK     (0xFFFF)
+#define CFG58_USB31PHY_CR_DATA_RD_START (16)
+
+#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
+
+#define CFGA0_VAUX_RESET		BIT(9)
+#define CFGA0_USB31C_RESET		BIT(8)
+#define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
+#define CFGA0_USB3PHY_RESET		BIT(1)
+#define CFGA0_USB2PHY_POR		BIT(0)
+
+#define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
+#define INTR_EN_XA_ACK_EVT_EN		BIT(0)
+
+#define CLK_RST_TCA_REF_CLK_EN		BIT(1)
+#define CLK_RST_SUSPEND_CLK_EN		BIT(0)
+
+#define GCFG_ROLE_HSTDEV		BIT(4)
+#define GCFG_OP_MODE			(3 << 0)
+#define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
+
+#define TCPC_VALID			BIT(4)
+#define TCPC_LOW_POWER_EN		BIT(3)
+#define TCPC_MUX_CONTROL_MASK		(3 << 0)
+#define TCPC_MUX_CONTROL_USB31		BIT(0)
+
+#define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
+
+#define VBUS_CTRL_POWERPRESENT_OVERRD	(3 << 2)
+#define VBUS_CTRL_VBUSVALID_OVERRD	(3 << 0)
+
+#define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xFDFEE4)
+#define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
+
+#define TX_VBOOST_LVL_REG		(0xf)
+#define TX_VBOOST_LVL_START		(6)
+#define TX_VBOOST_LVL_ENABLE		BIT(9)
+
+struct hi3670_priv {
+	struct device *dev;
+	struct regmap *peri_crg;
+	struct regmap *pctrl;
+	struct regmap *sctrl;
+	struct regmap *usb31misc;
+
+	u32 eye_diagram_param;
+	u32 tx_vboost_lvl;
+
+	u32 peri_crg_offset;
+	u32 pctrl_offset;
+	u32 usb31misc_offset;
+};
+
+static int hi3670_phy_cr_clk(struct regmap *usb31misc)
+{
+	int ret;
+
+	/* Clock up */
+	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
+				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
+	if (ret)
+		return ret;
+
+	/* Clock down */
+	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
+				 CFG54_USB31PHY_CR_CLK, 0);
+
+	return ret;
+}
+
+static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
+{
+	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
+				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
+}
+
+static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
+{
+	int ret;
+
+	if (direction)
+		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
+					 CFG54_USB31PHY_CR_WR_EN,
+					 CFG54_USB31PHY_CR_WR_EN);
+	else
+		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
+					 CFG54_USB31PHY_CR_RD_EN,
+					 CFG54_USB31PHY_CR_RD_EN);
+
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_clk(usb31misc);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
+				 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
+
+	return ret;
+}
+
+static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
+{
+	u32 reg;
+	int retry = 100000;
+	int ret;
+
+	while (retry-- > 0) {
+		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
+		if (ret)
+			return ret;
+		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
+			return 0;
+
+		ret = hi3670_phy_cr_clk(usb31misc);
+		if (ret)
+			return ret;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
+{
+	u32 reg;
+	int ret;
+
+	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
+	if (ret)
+		return ret;
+
+	reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT);
+	reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT);
+	ret = regmap_write(usb31misc, USB_MISC_CFG54, reg);
+
+	return ret;
+}
+
+static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
+{
+	int reg;
+	int i;
+	int ret;
+
+	for (i = 0; i < 100; i++) {
+		ret = hi3670_phy_cr_clk(usb31misc);
+		if (ret)
+			return ret;
+	}
+
+	ret = hi3670_phy_cr_set_sel(usb31misc);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_start(usb31misc, 0);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_wait_ack(usb31misc);
+	if (ret)
+		return ret;
+
+	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
+	if (ret)
+		return ret;
+
+	*val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) &
+		CFG58_USB31PHY_CR_DATA_MASK;
+
+	return 0;
+}
+
+static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < 100; i++) {
+		ret = hi3670_phy_cr_clk(usb31misc);
+		if (ret)
+			return ret;
+	}
+
+	ret = hi3670_phy_cr_set_sel(usb31misc);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(usb31misc, USB_MISC_CFG58,
+			   val & CFG58_USB31PHY_CR_DATA_MASK);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_start(usb31misc, 1);
+	if (ret)
+		return ret;
+
+	ret = hi3670_phy_cr_wait_ack(usb31misc);
+
+	return ret;
+}
+
+static int hi3670_phy_set_params(struct hi3670_priv *priv)
+{
+	u32 reg;
+	int ret;
+	int retry = 3;
+
+	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
+			   priv->eye_diagram_param);
+	if (ret) {
+		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
+		return ret;
+	}
+
+	while (retry-- > 0) {
+		ret = hi3670_phy_cr_read(priv->usb31misc,
+					 TX_VBOOST_LVL_REG, &reg);
+		if (!ret)
+			break;
+
+		if (ret != -ETIMEDOUT) {
+			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
+			return ret;
+		}
+	}
+	if (ret)
+		return ret;
+
+	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
+	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
+	if (ret)
+		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
+
+	return ret;
+}
+
+static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv)
+{
+	u32 reg;
+
+	if (!priv->sctrl) {
+		dev_err(priv->dev, "priv->sctrl is null!\n");
+		return 1;
+	}
+
+	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
+		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
+		return 1;
+	}
+
+	if ((reg & USB_CLK_SELECTED) == 0)
+		return 1;
+
+	return 0;
+}
+
+static int hi3670_config_phy_clock(struct hi3670_priv *priv)
+{
+	u32 val, mask;
+	int ret;
+
+	if (hi3670_is_abbclk_seleted(priv)) {
+		/* usb refclk iso disable */
+		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
+				   USB_REFCLK_ISO_EN);
+		if (ret)
+			goto out;
+
+		/* enable usb_tcxo_en */
+		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
+				   USB_TCXO_EN |
+				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
+
+		/* select usbphy clk from abb */
+		mask = SC_CLK_USB3PHY_3MUX1_SEL;
+		ret = regmap_update_bits(priv->pctrl,
+					 PCTRL_PERI_CTRL24, mask, 0);
+		if (ret)
+			goto out;
+
+		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
+					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
+		if (ret)
+			goto out;
+
+		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
+		if (ret)
+			goto out;
+		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
+		val |= CTRL7_USB2_REFCLKSEL_ABB;
+		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
+		if (ret)
+			goto out;
+
+		return 0;
+	}
+
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
+				 CFG54_USB3PHY_REF_USE_PAD,
+				 CFG54_USB3PHY_REF_USE_PAD);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
+				 CFGA0_USB2PHY_REFCLK_SELECT,
+				 CFGA0_USB2PHY_REFCLK_SELECT);
+	if (ret)
+		goto out;
+
+	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
+	if (ret)
+		goto out;
+	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
+	val |= CTRL7_USB2_REFCLKSEL_PAD;
+	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
+	if (ret)
+		goto out;
+
+	ret = regmap_write(priv->peri_crg,
+			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
+	return ret;
+}
+
+static int hi3670_config_tca(struct hi3670_priv *priv)
+{
+	u32 val, mask;
+	int ret;
+
+	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
+	if (ret)
+		goto out;
+
+	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
+			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
+	if (ret)
+		goto out;
+
+	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
+	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
+				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
+				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
+				 SYSMODE_CFG_TYPEC_DISABLE, 0);
+	if (ret)
+		goto out;
+
+	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
+	if (ret)
+		goto out;
+	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
+	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
+	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
+	if (ret)
+		goto out;
+
+	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
+			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
+	return ret;
+}
+
+static int hi3670_phy_init(struct phy *phy)
+{
+	struct hi3670_priv *priv = phy_get_drvdata(phy);
+	u32 val;
+	int ret;
+
+	/* assert controller */
+	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
+	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
+	if (ret)
+		goto out;
+
+	ret = hi3670_config_phy_clock(priv);
+	if (ret)
+		goto out;
+
+	/* Exit from IDDQ mode */
+	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
+				 CTRL5_USB2_SIDDQ, 0);
+	if (ret)
+		goto out;
+
+	/* Release USB31 PHY out of TestPowerDown mode */
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
+				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
+	if (ret)
+		goto out;
+
+	/* Deassert phy */
+	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
+	if (ret)
+		goto out;
+
+	usleep_range(100, 120);
+
+	/* Tell the PHY power is stable */
+	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
+	      CFG54_PHY0_PMA_PWR_STABLE;
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
+				 val, val);
+	if (ret)
+		goto out;
+
+	ret = hi3670_config_tca(priv);
+	if (ret)
+		goto out;
+
+	/* Enable SSC */
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
+				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
+				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
+	if (ret)
+		goto out;
+
+	/* Deassert controller */
+	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
+	if (ret)
+		goto out;
+
+	usleep_range(100, 120);
+
+	/* Set fake vbus valid signal */
+	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
+	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
+	if (ret)
+		goto out;
+
+	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
+	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
+	if (ret)
+		goto out;
+
+	usleep_range(100, 120);
+
+	ret = hi3670_phy_set_params(priv);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
+	return ret;
+}
+
+static int hi3670_phy_exit(struct phy *phy)
+{
+	struct hi3670_priv *priv = phy_get_drvdata(phy);
+	u32 mask;
+	int ret;
+
+	/* Assert phy */
+	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
+	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
+	if (ret)
+		goto out;
+
+	if (hi3670_is_abbclk_seleted(priv)) {
+		/* disable usb_tcxo_en */
+		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
+				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
+	} else {
+		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
+				   GT_CLK_USB2PHY_REF);
+		if (ret)
+			goto out;
+	}
+
+	return 0;
+out:
+	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
+	return ret;
+}
+
+static struct phy_ops hi3670_phy_ops = {
+	.init		= hi3670_phy_init,
+	.exit		= hi3670_phy_exit,
+	.owner		= THIS_MODULE,
+};
+
+static int hi3670_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct phy *phy;
+	struct hi3670_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
+							 "hisilicon,pericrg-syscon");
+	if (IS_ERR(priv->peri_crg)) {
+		dev_err(dev, "no hisilicon,pericrg-syscon\n");
+		return PTR_ERR(priv->peri_crg);
+	}
+
+	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
+						      "hisilicon,pctrl-syscon");
+	if (IS_ERR(priv->pctrl)) {
+		dev_err(dev, "no hisilicon,pctrl-syscon\n");
+		return PTR_ERR(priv->pctrl);
+	}
+
+	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
+						      "hisilicon,sctrl-syscon");
+	if (IS_ERR(priv->sctrl)) {
+		dev_err(dev, "no hisilicon,sctrl-syscon\n");
+		return PTR_ERR(priv->sctrl);
+	}
+
+	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
+	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(priv->usb31misc)) {
+		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
+		return PTR_ERR(priv->usb31misc);
+	}
+
+	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
+				 &priv->eye_diagram_param))
+		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
+
+	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
+				 &priv->tx_vboost_lvl))
+		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
+
+	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
+	if (IS_ERR(phy))
+		return PTR_ERR(phy);
+
+	phy_set_drvdata(phy, priv);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id hi3670_phy_of_match[] = {
+	{ .compatible = "hisilicon,hi3670-usb-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
+
+static struct platform_driver hi3670_phy_driver = {
+	.probe	= hi3670_phy_probe,
+	.driver = {
+		.name	= "hi3670-usb-phy",
+		.of_match_table	= hi3670_phy_of_match,
+	}
+};
+module_platform_driver(hi3670_phy_driver);
+
+MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index b29f5d5df134..0e97b5b9a56a 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,16 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-# to be placed at drivers/phy
-config PHY_HI3670_USB
-	tristate "hi3670 USB PHY support"
-	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
-	select GENERIC_PHY
-	select MFD_SYSCON
-	help
-	  Enable this to support the HISILICON HI3670 USB PHY.
-
-	  To compile this driver as a module, choose M here.
-
 # to be placed at drivers/spmi
 config SPMI_HISI3670
 	tristate "Hisilicon 3670 SPMI Controller"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 1924fadac952..9371dcc3d35b 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,7 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_PHY_HI3670_USB)		+= phy-hi3670-usb3.o
-
 obj-$(CONFIG_SPMI_HISI3670)		+= hisi-spmi-controller.o
 obj-$(CONFIG_MFD_HI6421_SPMI)		+= hi6421-spmi-pmic.o
 obj-$(CONFIG_REGULATOR_HI6421V600)	+= hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.c b/drivers/staging/hikey9xx/phy-hi3670-usb3.c
deleted file mode 100644
index 4fc013911a78..000000000000
--- a/drivers/staging/hikey9xx/phy-hi3670-usb3.c
+++ /dev/null
@@ -1,671 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
- *
- * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
- *		http://www.huawei.com
- *
- * Authors: Yu Chen <chenyu56@huawei.com>
- */
-
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <linux/phy/phy.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-#define SCTRL_SCDEEPSLEEPED		(0x0)
-#define USB_CLK_SELECTED		BIT(20)
-
-#define PERI_CRG_PEREN0			(0x00)
-#define PERI_CRG_PERDIS0		(0x04)
-#define PERI_CRG_PEREN4			(0x40)
-#define PERI_CRG_PERDIS4		(0x44)
-#define PERI_CRG_PERRSTEN4		(0x90)
-#define PERI_CRG_PERRSTDIS4		(0x94)
-#define PERI_CRG_ISODIS			(0x148)
-#define PERI_CRG_PEREN6			(0x410)
-#define PERI_CRG_PERDIS6		(0x414)
-
-#define USB_REFCLK_ISO_EN		BIT(25)
-
-#define GT_CLK_USB2PHY_REF		BIT(19)
-
-#define PCTRL_PERI_CTRL3		(0x10)
-#define PCTRL_PERI_CTRL3_MSK_START	(16)
-#define USB_TCXO_EN			BIT(1)
-
-#define PCTRL_PERI_CTRL24		(0x64)
-#define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
-
-#define USB3OTG_CTRL0			(0x00)
-#define USB3OTG_CTRL3			(0x0C)
-#define USB3OTG_CTRL4			(0x10)
-#define USB3OTG_CTRL5			(0x14)
-#define USB3OTG_CTRL7			(0x1C)
-#define USB_MISC_CFG50			(0x50)
-#define USB_MISC_CFG54			(0x54)
-#define USB_MISC_CFG58			(0x58)
-#define USB_MISC_CFG5C			(0x5C)
-#define USB_MISC_CFGA0			(0xA0)
-#define TCA_CLK_RST			(0x200)
-#define TCA_INTR_EN			(0x204)
-#define TCA_INTR_STS			(0x208)
-#define TCA_GCFG			(0x210)
-#define TCA_TCPC			(0x214)
-#define TCA_SYSMODE_CFG			(0x218)
-#define TCA_VBUS_CTRL			(0x240)
-
-#define CTRL0_USB3_VBUSVLD		BIT(7)
-#define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
-
-#define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
-#define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
-
-#define CTRL5_USB2_SIDDQ		BIT(0)
-
-#define CTRL7_USB2_REFCLKSEL_MASK	(3 << 3)
-#define CTRL7_USB2_REFCLKSEL_ABB	(3 << 3)
-#define CTRL7_USB2_REFCLKSEL_PAD	(2 << 3)
-
-#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
-
-#define CFG54_USB31PHY_CR_ADDR_MASK	(0xFFFF)
-#define CFG54_USB31PHY_CR_ADDR_SHIFT	(16)
-#define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
-#define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
-#define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
-#define CFG54_USB31PHY_CR_ACK		BIT(7)
-#define CFG54_USB31PHY_CR_WR_EN		BIT(5)
-#define CFG54_USB31PHY_CR_SEL		BIT(4)
-#define CFG54_USB31PHY_CR_RD_EN		BIT(3)
-#define CFG54_USB31PHY_CR_CLK		BIT(2)
-#define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
-
-#define CFG58_USB31PHY_CR_DATA_MASK     (0xFFFF)
-#define CFG58_USB31PHY_CR_DATA_RD_START (16)
-
-#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
-
-#define CFGA0_VAUX_RESET		BIT(9)
-#define CFGA0_USB31C_RESET		BIT(8)
-#define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
-#define CFGA0_USB3PHY_RESET		BIT(1)
-#define CFGA0_USB2PHY_POR		BIT(0)
-
-#define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
-#define INTR_EN_XA_ACK_EVT_EN		BIT(0)
-
-#define CLK_RST_TCA_REF_CLK_EN		BIT(1)
-#define CLK_RST_SUSPEND_CLK_EN		BIT(0)
-
-#define GCFG_ROLE_HSTDEV		BIT(4)
-#define GCFG_OP_MODE			(3 << 0)
-#define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
-
-#define TCPC_VALID			BIT(4)
-#define TCPC_LOW_POWER_EN		BIT(3)
-#define TCPC_MUX_CONTROL_MASK		(3 << 0)
-#define TCPC_MUX_CONTROL_USB31		BIT(0)
-
-#define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
-
-#define VBUS_CTRL_POWERPRESENT_OVERRD	(3 << 2)
-#define VBUS_CTRL_VBUSVALID_OVERRD	(3 << 0)
-
-#define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xFDFEE4)
-#define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
-
-#define TX_VBOOST_LVL_REG		(0xf)
-#define TX_VBOOST_LVL_START		(6)
-#define TX_VBOOST_LVL_ENABLE		BIT(9)
-
-struct hi3670_priv {
-	struct device *dev;
-	struct regmap *peri_crg;
-	struct regmap *pctrl;
-	struct regmap *sctrl;
-	struct regmap *usb31misc;
-
-	u32 eye_diagram_param;
-	u32 tx_vboost_lvl;
-
-	u32 peri_crg_offset;
-	u32 pctrl_offset;
-	u32 usb31misc_offset;
-};
-
-static int hi3670_phy_cr_clk(struct regmap *usb31misc)
-{
-	int ret;
-
-	/* Clock up */
-	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
-				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
-	if (ret)
-		return ret;
-
-	/* Clock down */
-	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
-				 CFG54_USB31PHY_CR_CLK, 0);
-
-	return ret;
-}
-
-static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
-{
-	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
-				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
-}
-
-static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
-{
-	int ret;
-
-	if (direction)
-		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
-					 CFG54_USB31PHY_CR_WR_EN,
-					 CFG54_USB31PHY_CR_WR_EN);
-	else
-		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
-					 CFG54_USB31PHY_CR_RD_EN,
-					 CFG54_USB31PHY_CR_RD_EN);
-
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_clk(usb31misc);
-	if (ret)
-		return ret;
-
-	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
-				 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
-
-	return ret;
-}
-
-static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
-{
-	u32 reg;
-	int retry = 100000;
-	int ret;
-
-	while (retry-- > 0) {
-		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
-		if (ret)
-			return ret;
-		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
-			return 0;
-
-		ret = hi3670_phy_cr_clk(usb31misc);
-		if (ret)
-			return ret;
-	}
-
-	return -ETIMEDOUT;
-}
-
-static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
-{
-	u32 reg;
-	int ret;
-
-	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
-	if (ret)
-		return ret;
-
-	reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT);
-	reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT);
-	ret = regmap_write(usb31misc, USB_MISC_CFG54, reg);
-
-	return ret;
-}
-
-static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
-{
-	int reg;
-	int i;
-	int ret;
-
-	for (i = 0; i < 100; i++) {
-		ret = hi3670_phy_cr_clk(usb31misc);
-		if (ret)
-			return ret;
-	}
-
-	ret = hi3670_phy_cr_set_sel(usb31misc);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_start(usb31misc, 0);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_wait_ack(usb31misc);
-	if (ret)
-		return ret;
-
-	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
-	if (ret)
-		return ret;
-
-	*val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) &
-		CFG58_USB31PHY_CR_DATA_MASK;
-
-	return 0;
-}
-
-static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
-{
-	int i;
-	int ret;
-
-	for (i = 0; i < 100; i++) {
-		ret = hi3670_phy_cr_clk(usb31misc);
-		if (ret)
-			return ret;
-	}
-
-	ret = hi3670_phy_cr_set_sel(usb31misc);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
-	if (ret)
-		return ret;
-
-	ret = regmap_write(usb31misc, USB_MISC_CFG58,
-			   val & CFG58_USB31PHY_CR_DATA_MASK);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_start(usb31misc, 1);
-	if (ret)
-		return ret;
-
-	ret = hi3670_phy_cr_wait_ack(usb31misc);
-
-	return ret;
-}
-
-static int hi3670_phy_set_params(struct hi3670_priv *priv)
-{
-	u32 reg;
-	int ret;
-	int retry = 3;
-
-	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
-			   priv->eye_diagram_param);
-	if (ret) {
-		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
-		return ret;
-	}
-
-	while (retry-- > 0) {
-		ret = hi3670_phy_cr_read(priv->usb31misc,
-					 TX_VBOOST_LVL_REG, &reg);
-		if (!ret)
-			break;
-
-		if (ret != -ETIMEDOUT) {
-			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
-			return ret;
-		}
-	}
-	if (ret)
-		return ret;
-
-	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
-	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
-	if (ret)
-		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
-
-	return ret;
-}
-
-static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv)
-{
-	u32 reg;
-
-	if (!priv->sctrl) {
-		dev_err(priv->dev, "priv->sctrl is null!\n");
-		return 1;
-	}
-
-	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
-		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
-		return 1;
-	}
-
-	if ((reg & USB_CLK_SELECTED) == 0)
-		return 1;
-
-	return 0;
-}
-
-static int hi3670_config_phy_clock(struct hi3670_priv *priv)
-{
-	u32 val, mask;
-	int ret;
-
-	if (hi3670_is_abbclk_seleted(priv)) {
-		/* usb refclk iso disable */
-		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
-				   USB_REFCLK_ISO_EN);
-		if (ret)
-			goto out;
-
-		/* enable usb_tcxo_en */
-		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
-				   USB_TCXO_EN |
-				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
-
-		/* select usbphy clk from abb */
-		mask = SC_CLK_USB3PHY_3MUX1_SEL;
-		ret = regmap_update_bits(priv->pctrl,
-					 PCTRL_PERI_CTRL24, mask, 0);
-		if (ret)
-			goto out;
-
-		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
-					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
-		if (ret)
-			goto out;
-
-		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
-		if (ret)
-			goto out;
-		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
-		val |= CTRL7_USB2_REFCLKSEL_ABB;
-		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
-		if (ret)
-			goto out;
-
-		return 0;
-	}
-
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
-				 CFG54_USB3PHY_REF_USE_PAD,
-				 CFG54_USB3PHY_REF_USE_PAD);
-	if (ret)
-		goto out;
-
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
-				 CFGA0_USB2PHY_REFCLK_SELECT,
-				 CFGA0_USB2PHY_REFCLK_SELECT);
-	if (ret)
-		goto out;
-
-	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
-	if (ret)
-		goto out;
-	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
-	val |= CTRL7_USB2_REFCLKSEL_PAD;
-	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
-	if (ret)
-		goto out;
-
-	ret = regmap_write(priv->peri_crg,
-			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
-	if (ret)
-		goto out;
-
-	return 0;
-out:
-	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
-	return ret;
-}
-
-static int hi3670_config_tca(struct hi3670_priv *priv)
-{
-	u32 val, mask;
-	int ret;
-
-	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
-	if (ret)
-		goto out;
-
-	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
-			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
-	if (ret)
-		goto out;
-
-	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
-	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
-	if (ret)
-		goto out;
-
-	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
-				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
-				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
-	if (ret)
-		goto out;
-
-	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
-				 SYSMODE_CFG_TYPEC_DISABLE, 0);
-	if (ret)
-		goto out;
-
-	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
-	if (ret)
-		goto out;
-	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
-	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
-	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
-	if (ret)
-		goto out;
-
-	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
-			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
-	if (ret)
-		goto out;
-
-	return 0;
-out:
-	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
-	return ret;
-}
-
-static int hi3670_phy_init(struct phy *phy)
-{
-	struct hi3670_priv *priv = phy_get_drvdata(phy);
-	u32 val;
-	int ret;
-
-	/* assert controller */
-	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
-	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
-	if (ret)
-		goto out;
-
-	ret = hi3670_config_phy_clock(priv);
-	if (ret)
-		goto out;
-
-	/* Exit from IDDQ mode */
-	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
-				 CTRL5_USB2_SIDDQ, 0);
-	if (ret)
-		goto out;
-
-	/* Release USB31 PHY out of TestPowerDown mode */
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
-				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
-	if (ret)
-		goto out;
-
-	/* Deassert phy */
-	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
-	if (ret)
-		goto out;
-
-	usleep_range(100, 120);
-
-	/* Tell the PHY power is stable */
-	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
-	      CFG54_PHY0_PMA_PWR_STABLE;
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
-				 val, val);
-	if (ret)
-		goto out;
-
-	ret = hi3670_config_tca(priv);
-	if (ret)
-		goto out;
-
-	/* Enable SSC */
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
-				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
-				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
-	if (ret)
-		goto out;
-
-	/* Deassert controller */
-	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
-	if (ret)
-		goto out;
-
-	usleep_range(100, 120);
-
-	/* Set fake vbus valid signal */
-	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
-	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
-	if (ret)
-		goto out;
-
-	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
-	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
-	if (ret)
-		goto out;
-
-	usleep_range(100, 120);
-
-	ret = hi3670_phy_set_params(priv);
-	if (ret)
-		goto out;
-
-	return 0;
-out:
-	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
-	return ret;
-}
-
-static int hi3670_phy_exit(struct phy *phy)
-{
-	struct hi3670_priv *priv = phy_get_drvdata(phy);
-	u32 mask;
-	int ret;
-
-	/* Assert phy */
-	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
-	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
-	if (ret)
-		goto out;
-
-	if (hi3670_is_abbclk_seleted(priv)) {
-		/* disable usb_tcxo_en */
-		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
-				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
-	} else {
-		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
-				   GT_CLK_USB2PHY_REF);
-		if (ret)
-			goto out;
-	}
-
-	return 0;
-out:
-	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
-	return ret;
-}
-
-static struct phy_ops hi3670_phy_ops = {
-	.init		= hi3670_phy_init,
-	.exit		= hi3670_phy_exit,
-	.owner		= THIS_MODULE,
-};
-
-static int hi3670_phy_probe(struct platform_device *pdev)
-{
-	struct phy_provider *phy_provider;
-	struct device *dev = &pdev->dev;
-	struct phy *phy;
-	struct hi3670_priv *priv;
-
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->dev = dev;
-	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
-							 "hisilicon,pericrg-syscon");
-	if (IS_ERR(priv->peri_crg)) {
-		dev_err(dev, "no hisilicon,pericrg-syscon\n");
-		return PTR_ERR(priv->peri_crg);
-	}
-
-	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
-						      "hisilicon,pctrl-syscon");
-	if (IS_ERR(priv->pctrl)) {
-		dev_err(dev, "no hisilicon,pctrl-syscon\n");
-		return PTR_ERR(priv->pctrl);
-	}
-
-	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
-						      "hisilicon,sctrl-syscon");
-	if (IS_ERR(priv->sctrl)) {
-		dev_err(dev, "no hisilicon,sctrl-syscon\n");
-		return PTR_ERR(priv->sctrl);
-	}
-
-	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
-	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
-	if (IS_ERR(priv->usb31misc)) {
-		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
-		return PTR_ERR(priv->usb31misc);
-	}
-
-	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
-				 &priv->eye_diagram_param))
-		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
-
-	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
-				 &priv->tx_vboost_lvl))
-		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
-
-	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
-	if (IS_ERR(phy))
-		return PTR_ERR(phy);
-
-	phy_set_drvdata(phy, priv);
-	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-	return PTR_ERR_OR_ZERO(phy_provider);
-}
-
-static const struct of_device_id hi3670_phy_of_match[] = {
-	{ .compatible = "hisilicon,hi3670-usb-phy" },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
-
-static struct platform_driver hi3670_phy_driver = {
-	.probe	= hi3670_phy_probe,
-	.driver = {
-		.name	= "hi3670-usb-phy",
-		.of_match_table	= hi3670_phy_of_match,
-	}
-};
-module_platform_driver(hi3670_phy_driver);
-
-MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml b/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
deleted file mode 100644
index 125a5d6546ae..000000000000
--- a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Hisilicon Kirin970 USB PHY
-
-maintainers:
-  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-description: |+
-  Bindings for USB3 PHY on HiSilicon Kirin 970.
-
-properties:
-  compatible:
-    const: hisilicon,hi3670-usb-phy
-
-  "#phy-cells":
-    const: 0
-
-  hisilicon,pericrg-syscon:
-    $ref: '/schemas/types.yaml#/definitions/phandle'
-    description: phandle of syscon used to control iso refclk.
-
-  hisilicon,pctrl-syscon:
-    $ref: '/schemas/types.yaml#/definitions/phandle'
-    description: phandle of syscon used to control usb tcxo.
-
-  hisilicon,sctrl-syscon:
-    $ref: '/schemas/types.yaml#/definitions/phandle'
-    description: phandle of syscon used to control phy deep sleep.
-
-  hisilicon,eye-diagram-param:
-    $ref: /schemas/types.yaml#/definitions/uint32
-    description: Eye diagram for phy.
-
-  hisilicon,tx-vboost-lvl:
-    $ref: /schemas/types.yaml#/definitions/uint32
-    description: TX level vboost for phy.
-
-required:
-  - compatible
-  - hisilicon,pericrg-syscon
-  - hisilicon,pctrl-syscon
-  - hisilicon,sctrl-syscon
-  - hisilicon,eye-diagram-param
-  - hisilicon,tx-vboost-lvl
-  - "#phy-cells"
-
-additionalProperties: false
-
-examples:
-  - |
-    bus {
-      #address-cells = <2>;
-      #size-cells = <2>;
-
-      usb3_otg_bc: usb3_otg_bc@ff200000 {
-        compatible = "syscon", "simple-mfd";
-        reg = <0x0 0xff200000 0x0 0x1000>;
-
-        usb_phy {
-          compatible = "hisilicon,hi3670-usb-phy";
-          #phy-cells = <0>;
-          hisilicon,pericrg-syscon = <&crg_ctrl>;
-          hisilicon,pctrl-syscon = <&pctrl>;
-          hisilicon,sctrl-syscon = <&sctrl>;
-          hisilicon,eye-diagram-param = <0xfdfee4>;
-          hisilicon,tx-vboost-lvl = <0x5>;
-        };
-      };
-    };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 15:32   ` Rob Herring
  2020-11-16 12:59 ` [PATCH 3/8] mfd: " Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring, Stephen Boyd
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Colin Ian King, Dan Carpenter,
	Greg Kroah-Hartman, Mayulong, YueHaibing, devel, devicetree,
	linux-arm-msm, linux-kernel

The Hisilicon 6421v600 SPMI driver is ready for mainstream.

So, move it from staging.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../spmi/hisilicon,hisi-spmi-controller.yaml  |  62 +++
 MAINTAINERS                                   |   7 +
 drivers/spmi/Kconfig                          |   9 +
 drivers/spmi/Makefile                         |   1 +
 drivers/spmi/hisi-spmi-controller.c           | 358 ++++++++++++++++++
 drivers/staging/hikey9xx/Kconfig              |  11 -
 drivers/staging/hikey9xx/Makefile             |   1 -
 .../staging/hikey9xx/hisi-spmi-controller.c   | 358 ------------------
 .../hisilicon,hisi-spmi-controller.yaml       |  62 ---
 9 files changed, 437 insertions(+), 432 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
 create mode 100644 drivers/spmi/hisi-spmi-controller.c
 delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
 delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml

diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
new file mode 100644
index 000000000000..f2a56fa4e78e
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon SPMI controller
+
+maintainers:
+  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+description: |
+  The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
+  It is a MIPI System Power Management (SPMI) controller.
+
+  The PMIC part is provided by
+  drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
+
+properties:
+  $nodename:
+    pattern: "spmi@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,kirin970-spmi-controller
+
+  reg:
+    maxItems: 1
+
+  spmi-channel:
+    description: |
+      number of the Kirin 970 SPMI channel where the SPMI devices are connected.
+
+required:
+ - compatible
+ - reg
+ - spmi-channel
+
+patternProperties:
+  "^pmic@[0-9a-f]$":
+    description: |
+      PMIC properties, which are specific to the used SPMI PMIC device(s).
+      When used in combination with HiSilicon 6421v600, the properties
+      are documented at
+      drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
+
+examples:
+  - |
+    bus {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      spmi: spmi@fff24000 {
+        compatible = "hisilicon,kirin970-spmi-controller";
+        status = "ok";
+        reg = <0x0 0xfff24000 0x0 0x1000>;
+        spmi-channel = <2>;
+
+        pmic@0 {
+          /* pmic properties */
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 14266bb79ff8..14bc7b45ed50 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7987,6 +7987,13 @@ F:	drivers/crypto/hisilicon/sec2/sec_crypto.c
 F:	drivers/crypto/hisilicon/sec2/sec_crypto.h
 F:	drivers/crypto/hisilicon/sec2/sec_main.c
 
+HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970
+M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
+F:	drivers/spmi/hisi-spmi-controller.c
+
 HISILICON STAGING DRIVERS FOR HIKEY 960/970
 M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
 L:	devel@driverdev.osuosl.org
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index a53bad541f1a..2874b6c26028 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -11,6 +11,15 @@ menuconfig SPMI
 
 if SPMI
 
+config SPMI_HISI3670
+	tristate "Hisilicon 3670 SPMI Controller"
+	select IRQ_DOMAIN_HIERARCHY
+	depends on HAS_IOMEM
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in SPMI PMIC Arbiter interface on Hisilicon 3670
+	  processors.
+
 config SPMI_MSM_PMIC_ARB
 	tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
 	select IRQ_DOMAIN_HIERARCHY
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 55a94cadeffe..6e092e6f290c 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,4 +4,5 @@
 #
 obj-$(CONFIG_SPMI)	+= spmi.o
 
+obj-$(CONFIG_SPMI_HISI3670)	+= hisi-spmi-controller.o
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
new file mode 100644
index 000000000000..f831c43f4783
--- /dev/null
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/*
+ * SPMI register addr
+ */
+#define SPMI_CHANNEL_OFFSET				0x0300
+#define SPMI_SLAVE_OFFSET				0x20
+
+#define SPMI_APB_SPMI_CMD_BASE_ADDR			0x0100
+
+#define SPMI_APB_SPMI_WDATA0_BASE_ADDR			0x0104
+#define SPMI_APB_SPMI_WDATA1_BASE_ADDR			0x0108
+#define SPMI_APB_SPMI_WDATA2_BASE_ADDR			0x010c
+#define SPMI_APB_SPMI_WDATA3_BASE_ADDR			0x0110
+
+#define SPMI_APB_SPMI_STATUS_BASE_ADDR			0x0200
+
+#define SPMI_APB_SPMI_RDATA0_BASE_ADDR			0x0204
+#define SPMI_APB_SPMI_RDATA1_BASE_ADDR			0x0208
+#define SPMI_APB_SPMI_RDATA2_BASE_ADDR			0x020c
+#define SPMI_APB_SPMI_RDATA3_BASE_ADDR			0x0210
+
+#define SPMI_PER_DATAREG_BYTE				4
+/*
+ * SPMI cmd register
+ */
+#define SPMI_APB_SPMI_CMD_EN				BIT(31)
+#define SPMI_APB_SPMI_CMD_TYPE_OFFSET			24
+#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET			20
+#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET		16
+#define SPMI_APB_SPMI_CMD_ADDR_OFFSET			0
+
+/* Command Opcodes */
+
+enum spmi_controller_cmd_op_code {
+	SPMI_CMD_REG_ZERO_WRITE = 0,
+	SPMI_CMD_REG_WRITE = 1,
+	SPMI_CMD_REG_READ = 2,
+	SPMI_CMD_EXT_REG_WRITE = 3,
+	SPMI_CMD_EXT_REG_READ = 4,
+	SPMI_CMD_EXT_REG_WRITE_L = 5,
+	SPMI_CMD_EXT_REG_READ_L = 6,
+	SPMI_CMD_REG_RESET = 7,
+	SPMI_CMD_REG_SLEEP = 8,
+	SPMI_CMD_REG_SHUTDOWN = 9,
+	SPMI_CMD_REG_WAKEUP = 10,
+};
+
+/*
+ * SPMI status register
+ */
+#define SPMI_APB_TRANS_DONE			BIT(0)
+#define SPMI_APB_TRANS_FAIL			BIT(2)
+
+/* Command register fields */
+#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT	16
+
+/* Maximum number of support PMIC peripherals */
+#define SPMI_CONTROLLER_TIMEOUT_US		1000
+#define SPMI_CONTROLLER_MAX_TRANS_BYTES		16
+
+struct spmi_controller_dev {
+	struct spmi_controller	*controller;
+	struct device		*dev;
+	void __iomem		*base;
+	spinlock_t		lock;
+	u32			channel;
+};
+
+static int spmi_controller_wait_for_done(struct device *dev,
+					 struct spmi_controller_dev *ctrl_dev,
+					 void __iomem *base, u8 sid, u16 addr)
+{
+	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
+	u32 status, offset;
+
+	offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
+	offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
+
+	do {
+		status = readl(base + offset);
+
+		if (status & SPMI_APB_TRANS_DONE) {
+			if (status & SPMI_APB_TRANS_FAIL) {
+				dev_err(dev, "%s: transaction failed (0x%x)\n",
+					__func__, status);
+				return -EIO;
+			}
+			dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
+			return 0;
+		}
+		udelay(1);
+	} while (timeout--);
+
+	dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
+	return -ETIMEDOUT;
+}
+
+static int spmi_read_cmd(struct spmi_controller *ctrl,
+			 u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+	unsigned long flags;
+	u8 *buf = __buf;
+	u32 cmd, data;
+	int rc;
+	u8 op_code, i;
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	switch (opc) {
+	case SPMI_CMD_READ:
+		op_code = SPMI_CMD_REG_READ;
+		break;
+	case SPMI_CMD_EXT_READ:
+		op_code = SPMI_CMD_EXT_REG_READ;
+		break;
+	case SPMI_CMD_EXT_READL:
+		op_code = SPMI_CMD_EXT_REG_READ_L;
+		break;
+	default:
+		dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
+		return -EINVAL;
+	}
+
+	cmd = SPMI_APB_SPMI_CMD_EN |
+	     (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+	     ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+	     ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+	     ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
+
+	spin_lock_irqsave(&spmi_controller->lock, flags);
+
+	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+					   spmi_controller->base, slave_id, slave_addr);
+	if (rc)
+		goto done;
+
+	for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+		data = readl(spmi_controller->base + chnl_ofst +
+			     SPMI_SLAVE_OFFSET * slave_id +
+			     SPMI_APB_SPMI_RDATA0_BASE_ADDR +
+			     i * SPMI_PER_DATAREG_BYTE);
+		data = be32_to_cpu((__be32)data);
+		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+			memcpy(buf, &data, sizeof(data));
+			buf += sizeof(data);
+		} else {
+			memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
+			buf += (bc % SPMI_PER_DATAREG_BYTE);
+		}
+	}
+
+done:
+	spin_unlock_irqrestore(&spmi_controller->lock, flags);
+	if (rc)
+		dev_err(&ctrl->dev,
+			"spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
+			opc, slave_id, slave_addr, bc + 1);
+	else
+		dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
+			__func__, slave_id, slave_addr, (int)bc, __buf);
+
+	return rc;
+}
+
+static int spmi_write_cmd(struct spmi_controller *ctrl,
+			  u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+	const u8 *buf = __buf;
+	unsigned long flags;
+	u32 cmd, data;
+	int rc;
+	u8 op_code, i;
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	switch (opc) {
+	case SPMI_CMD_WRITE:
+		op_code = SPMI_CMD_REG_WRITE;
+		break;
+	case SPMI_CMD_EXT_WRITE:
+		op_code = SPMI_CMD_EXT_REG_WRITE;
+		break;
+	case SPMI_CMD_EXT_WRITEL:
+		op_code = SPMI_CMD_EXT_REG_WRITE_L;
+		break;
+	default:
+		dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
+		return -EINVAL;
+	}
+
+	cmd = SPMI_APB_SPMI_CMD_EN |
+	      (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+	      ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+	      ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
+	      ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
+
+	/* Write data to FIFOs */
+	spin_lock_irqsave(&spmi_controller->lock, flags);
+
+	for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+		data = 0;
+		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+			memcpy(&data, buf, sizeof(data));
+			buf += sizeof(data);
+		} else {
+			memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
+			buf += (bc % SPMI_PER_DATAREG_BYTE);
+		}
+
+		writel((u32)cpu_to_be32(data),
+		       spmi_controller->base + chnl_ofst +
+		       SPMI_APB_SPMI_WDATA0_BASE_ADDR +
+		       SPMI_PER_DATAREG_BYTE * i);
+	}
+
+	/* Start the transaction */
+	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+					   spmi_controller->base, slave_id,
+					   slave_addr);
+	spin_unlock_irqrestore(&spmi_controller->lock, flags);
+
+	if (rc)
+		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
+			opc, slave_id, slave_addr, bc);
+	else
+		dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
+			__func__, slave_id, slave_addr, (int)bc, __buf);
+
+	return rc;
+}
+
+static int spmi_controller_probe(struct platform_device *pdev)
+{
+	struct spmi_controller_dev *spmi_controller;
+	struct spmi_controller *ctrl;
+	struct resource *iores;
+	int ret;
+
+	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+	if (!ctrl) {
+		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
+		return -ENOMEM;
+	}
+	spmi_controller = spmi_controller_get_drvdata(ctrl);
+	spmi_controller->controller = ctrl;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores) {
+		dev_err(&pdev->dev, "can not get resource!\n");
+		return -EINVAL;
+	}
+
+	spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
+					     resource_size(iores));
+	if (!spmi_controller->base) {
+		dev_err(&pdev->dev, "can not remap base addr!\n");
+		return -EADDRNOTAVAIL;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
+				   &spmi_controller->channel);
+	if (ret) {
+		dev_err(&pdev->dev, "can not get channel\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, spmi_controller);
+	dev_set_drvdata(&ctrl->dev, spmi_controller);
+
+	spin_lock_init(&spmi_controller->lock);
+
+	ctrl->nr = spmi_controller->channel;
+	ctrl->dev.parent = pdev->dev.parent;
+	ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
+
+	/* Callbacks */
+	ctrl->read_cmd = spmi_read_cmd;
+	ctrl->write_cmd = spmi_write_cmd;
+
+	ret = spmi_controller_add(ctrl);
+	if (ret)
+		dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
+
+	return ret;
+}
+
+static int spmi_del_controller(struct platform_device *pdev)
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+	spmi_controller_remove(ctrl);
+	kfree(ctrl);
+	return 0;
+}
+
+static const struct of_device_id spmi_controller_match_table[] = {
+	{
+		.compatible = "hisilicon,kirin970-spmi-controller",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
+
+static struct platform_driver spmi_controller_driver = {
+	.probe		= spmi_controller_probe,
+	.remove		= spmi_del_controller,
+	.driver		= {
+		.name	= "hisi_spmi_controller",
+		.of_match_table = spmi_controller_match_table,
+	},
+};
+
+static int __init spmi_controller_init(void)
+{
+	return platform_driver_register(&spmi_controller_driver);
+}
+postcore_initcall(spmi_controller_init);
+
+static void __exit spmi_controller_exit(void)
+{
+	platform_driver_unregister(&spmi_controller_driver);
+}
+module_exit(spmi_controller_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:spmi_controller");
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index 0e97b5b9a56a..69392e42cd0d 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,16 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-# to be placed at drivers/spmi
-config SPMI_HISI3670
-	tristate "Hisilicon 3670 SPMI Controller"
-	select IRQ_DOMAIN_HIERARCHY
-	depends on HAS_IOMEM
-	depends on SPMI
-	help
-	  If you say yes to this option, support will be included for the
-	  built-in SPMI PMIC Arbiter interface on Hisilicon 3670
-	  processors.
-
 # to be placed at drivers/mfd
 config MFD_HI6421_SPMI
 	tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 9371dcc3d35b..347880fd378f 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,5 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_SPMI_HISI3670)		+= hisi-spmi-controller.o
 obj-$(CONFIG_MFD_HI6421_SPMI)		+= hi6421-spmi-pmic.o
 obj-$(CONFIG_REGULATOR_HI6421V600)	+= hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c
deleted file mode 100644
index f831c43f4783..000000000000
--- a/drivers/staging/hikey9xx/hisi-spmi-controller.c
+++ /dev/null
@@ -1,358 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-/*
- * SPMI register addr
- */
-#define SPMI_CHANNEL_OFFSET				0x0300
-#define SPMI_SLAVE_OFFSET				0x20
-
-#define SPMI_APB_SPMI_CMD_BASE_ADDR			0x0100
-
-#define SPMI_APB_SPMI_WDATA0_BASE_ADDR			0x0104
-#define SPMI_APB_SPMI_WDATA1_BASE_ADDR			0x0108
-#define SPMI_APB_SPMI_WDATA2_BASE_ADDR			0x010c
-#define SPMI_APB_SPMI_WDATA3_BASE_ADDR			0x0110
-
-#define SPMI_APB_SPMI_STATUS_BASE_ADDR			0x0200
-
-#define SPMI_APB_SPMI_RDATA0_BASE_ADDR			0x0204
-#define SPMI_APB_SPMI_RDATA1_BASE_ADDR			0x0208
-#define SPMI_APB_SPMI_RDATA2_BASE_ADDR			0x020c
-#define SPMI_APB_SPMI_RDATA3_BASE_ADDR			0x0210
-
-#define SPMI_PER_DATAREG_BYTE				4
-/*
- * SPMI cmd register
- */
-#define SPMI_APB_SPMI_CMD_EN				BIT(31)
-#define SPMI_APB_SPMI_CMD_TYPE_OFFSET			24
-#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET			20
-#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET		16
-#define SPMI_APB_SPMI_CMD_ADDR_OFFSET			0
-
-/* Command Opcodes */
-
-enum spmi_controller_cmd_op_code {
-	SPMI_CMD_REG_ZERO_WRITE = 0,
-	SPMI_CMD_REG_WRITE = 1,
-	SPMI_CMD_REG_READ = 2,
-	SPMI_CMD_EXT_REG_WRITE = 3,
-	SPMI_CMD_EXT_REG_READ = 4,
-	SPMI_CMD_EXT_REG_WRITE_L = 5,
-	SPMI_CMD_EXT_REG_READ_L = 6,
-	SPMI_CMD_REG_RESET = 7,
-	SPMI_CMD_REG_SLEEP = 8,
-	SPMI_CMD_REG_SHUTDOWN = 9,
-	SPMI_CMD_REG_WAKEUP = 10,
-};
-
-/*
- * SPMI status register
- */
-#define SPMI_APB_TRANS_DONE			BIT(0)
-#define SPMI_APB_TRANS_FAIL			BIT(2)
-
-/* Command register fields */
-#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT	16
-
-/* Maximum number of support PMIC peripherals */
-#define SPMI_CONTROLLER_TIMEOUT_US		1000
-#define SPMI_CONTROLLER_MAX_TRANS_BYTES		16
-
-struct spmi_controller_dev {
-	struct spmi_controller	*controller;
-	struct device		*dev;
-	void __iomem		*base;
-	spinlock_t		lock;
-	u32			channel;
-};
-
-static int spmi_controller_wait_for_done(struct device *dev,
-					 struct spmi_controller_dev *ctrl_dev,
-					 void __iomem *base, u8 sid, u16 addr)
-{
-	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
-	u32 status, offset;
-
-	offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
-	offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
-
-	do {
-		status = readl(base + offset);
-
-		if (status & SPMI_APB_TRANS_DONE) {
-			if (status & SPMI_APB_TRANS_FAIL) {
-				dev_err(dev, "%s: transaction failed (0x%x)\n",
-					__func__, status);
-				return -EIO;
-			}
-			dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
-			return 0;
-		}
-		udelay(1);
-	} while (timeout--);
-
-	dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
-	return -ETIMEDOUT;
-}
-
-static int spmi_read_cmd(struct spmi_controller *ctrl,
-			 u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
-{
-	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
-	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
-	unsigned long flags;
-	u8 *buf = __buf;
-	u32 cmd, data;
-	int rc;
-	u8 op_code, i;
-
-	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-		dev_err(&ctrl->dev,
-			"spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
-			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
-		return  -EINVAL;
-	}
-
-	switch (opc) {
-	case SPMI_CMD_READ:
-		op_code = SPMI_CMD_REG_READ;
-		break;
-	case SPMI_CMD_EXT_READ:
-		op_code = SPMI_CMD_EXT_REG_READ;
-		break;
-	case SPMI_CMD_EXT_READL:
-		op_code = SPMI_CMD_EXT_REG_READ_L;
-		break;
-	default:
-		dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
-		return -EINVAL;
-	}
-
-	cmd = SPMI_APB_SPMI_CMD_EN |
-	     (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
-	     ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
-	     ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
-	     ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
-
-	spin_lock_irqsave(&spmi_controller->lock, flags);
-
-	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
-
-	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
-					   spmi_controller->base, slave_id, slave_addr);
-	if (rc)
-		goto done;
-
-	for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
-		data = readl(spmi_controller->base + chnl_ofst +
-			     SPMI_SLAVE_OFFSET * slave_id +
-			     SPMI_APB_SPMI_RDATA0_BASE_ADDR +
-			     i * SPMI_PER_DATAREG_BYTE);
-		data = be32_to_cpu((__be32)data);
-		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
-			memcpy(buf, &data, sizeof(data));
-			buf += sizeof(data);
-		} else {
-			memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
-			buf += (bc % SPMI_PER_DATAREG_BYTE);
-		}
-	}
-
-done:
-	spin_unlock_irqrestore(&spmi_controller->lock, flags);
-	if (rc)
-		dev_err(&ctrl->dev,
-			"spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
-			opc, slave_id, slave_addr, bc + 1);
-	else
-		dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
-			__func__, slave_id, slave_addr, (int)bc, __buf);
-
-	return rc;
-}
-
-static int spmi_write_cmd(struct spmi_controller *ctrl,
-			  u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
-{
-	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
-	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
-	const u8 *buf = __buf;
-	unsigned long flags;
-	u32 cmd, data;
-	int rc;
-	u8 op_code, i;
-
-	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-		dev_err(&ctrl->dev,
-			"spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
-			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
-		return  -EINVAL;
-	}
-
-	switch (opc) {
-	case SPMI_CMD_WRITE:
-		op_code = SPMI_CMD_REG_WRITE;
-		break;
-	case SPMI_CMD_EXT_WRITE:
-		op_code = SPMI_CMD_EXT_REG_WRITE;
-		break;
-	case SPMI_CMD_EXT_WRITEL:
-		op_code = SPMI_CMD_EXT_REG_WRITE_L;
-		break;
-	default:
-		dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
-		return -EINVAL;
-	}
-
-	cmd = SPMI_APB_SPMI_CMD_EN |
-	      (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
-	      ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
-	      ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
-	      ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
-
-	/* Write data to FIFOs */
-	spin_lock_irqsave(&spmi_controller->lock, flags);
-
-	for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
-		data = 0;
-		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
-			memcpy(&data, buf, sizeof(data));
-			buf += sizeof(data);
-		} else {
-			memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
-			buf += (bc % SPMI_PER_DATAREG_BYTE);
-		}
-
-		writel((u32)cpu_to_be32(data),
-		       spmi_controller->base + chnl_ofst +
-		       SPMI_APB_SPMI_WDATA0_BASE_ADDR +
-		       SPMI_PER_DATAREG_BYTE * i);
-	}
-
-	/* Start the transaction */
-	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
-
-	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
-					   spmi_controller->base, slave_id,
-					   slave_addr);
-	spin_unlock_irqrestore(&spmi_controller->lock, flags);
-
-	if (rc)
-		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
-			opc, slave_id, slave_addr, bc);
-	else
-		dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
-			__func__, slave_id, slave_addr, (int)bc, __buf);
-
-	return rc;
-}
-
-static int spmi_controller_probe(struct platform_device *pdev)
-{
-	struct spmi_controller_dev *spmi_controller;
-	struct spmi_controller *ctrl;
-	struct resource *iores;
-	int ret;
-
-	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
-	if (!ctrl) {
-		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
-		return -ENOMEM;
-	}
-	spmi_controller = spmi_controller_get_drvdata(ctrl);
-	spmi_controller->controller = ctrl;
-
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!iores) {
-		dev_err(&pdev->dev, "can not get resource!\n");
-		return -EINVAL;
-	}
-
-	spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
-					     resource_size(iores));
-	if (!spmi_controller->base) {
-		dev_err(&pdev->dev, "can not remap base addr!\n");
-		return -EADDRNOTAVAIL;
-	}
-
-	ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
-				   &spmi_controller->channel);
-	if (ret) {
-		dev_err(&pdev->dev, "can not get channel\n");
-		return -ENODEV;
-	}
-
-	platform_set_drvdata(pdev, spmi_controller);
-	dev_set_drvdata(&ctrl->dev, spmi_controller);
-
-	spin_lock_init(&spmi_controller->lock);
-
-	ctrl->nr = spmi_controller->channel;
-	ctrl->dev.parent = pdev->dev.parent;
-	ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
-
-	/* Callbacks */
-	ctrl->read_cmd = spmi_read_cmd;
-	ctrl->write_cmd = spmi_write_cmd;
-
-	ret = spmi_controller_add(ctrl);
-	if (ret)
-		dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
-
-	return ret;
-}
-
-static int spmi_del_controller(struct platform_device *pdev)
-{
-	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-
-	spmi_controller_remove(ctrl);
-	kfree(ctrl);
-	return 0;
-}
-
-static const struct of_device_id spmi_controller_match_table[] = {
-	{
-		.compatible = "hisilicon,kirin970-spmi-controller",
-	},
-	{}
-};
-MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
-
-static struct platform_driver spmi_controller_driver = {
-	.probe		= spmi_controller_probe,
-	.remove		= spmi_del_controller,
-	.driver		= {
-		.name	= "hisi_spmi_controller",
-		.of_match_table = spmi_controller_match_table,
-	},
-};
-
-static int __init spmi_controller_init(void)
-{
-	return platform_driver_register(&spmi_controller_driver);
-}
-postcore_initcall(spmi_controller_init);
-
-static void __exit spmi_controller_exit(void)
-{
-	platform_driver_unregister(&spmi_controller_driver);
-}
-module_exit(spmi_controller_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:spmi_controller");
diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
deleted file mode 100644
index f2a56fa4e78e..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
+++ /dev/null
@@ -1,62 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: HiSilicon SPMI controller
-
-maintainers:
-  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |
-  The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
-  It is a MIPI System Power Management (SPMI) controller.
-
-  The PMIC part is provided by
-  drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-properties:
-  $nodename:
-    pattern: "spmi@[0-9a-f]"
-
-  compatible:
-    const: hisilicon,kirin970-spmi-controller
-
-  reg:
-    maxItems: 1
-
-  spmi-channel:
-    description: |
-      number of the Kirin 970 SPMI channel where the SPMI devices are connected.
-
-required:
- - compatible
- - reg
- - spmi-channel
-
-patternProperties:
-  "^pmic@[0-9a-f]$":
-    description: |
-      PMIC properties, which are specific to the used SPMI PMIC device(s).
-      When used in combination with HiSilicon 6421v600, the properties
-      are documented at
-      drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-examples:
-  - |
-    bus {
-      #address-cells = <2>;
-      #size-cells = <2>;
-
-      spmi: spmi@fff24000 {
-        compatible = "hisilicon,kirin970-spmi-controller";
-        status = "ok";
-        reg = <0x0 0xfff24000 0x0 0x1000>;
-        spmi-channel = <2>;
-
-        pmic@0 {
-          /* pmic properties */
-        };
-      };
-    };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/8] mfd: hi6421-spmi-pmic: move driver from staging
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 15:32   ` Rob Herring
  2020-11-16 12:59 ` [PATCH 4/8] regulator: hi6421v600-regulator: move it " Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring, Lee Jones
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Greg Kroah-Hartman, Mayulong, devel,
	devicetree, linux-kernel

This driver is ready for mainstream. So, move it out of staging.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 159 ++++++++
 MAINTAINERS                                   |   7 +
 drivers/mfd/Kconfig                           |  15 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/hi6421-spmi-pmic.c                | 342 ++++++++++++++++++
 drivers/staging/hikey9xx/Kconfig              |  16 -
 drivers/staging/hikey9xx/Makefile             |   1 -
 drivers/staging/hikey9xx/hi6421-spmi-pmic.c   | 342 ------------------
 .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml  | 159 --------
 9 files changed, 524 insertions(+), 518 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
 delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
 delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml

diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
new file mode 100644
index 000000000000..80e74c261e05
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon 6421v600 SPMI PMIC
+
+maintainers:
+  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+description: |
+  HiSilicon 6421v600 should be connected inside a MIPI System Power Management
+  (SPMI) bus. It provides interrupts and power supply.
+
+  The GPIO and interrupt settings are represented as part of the top-level PMIC
+  node.
+
+  The SPMI controller part is provided by
+  drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
+
+properties:
+  $nodename:
+    pattern: "pmic@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,hi6421v600-spmi
+
+  reg:
+    maxItems: 1
+
+  '#interrupt-cells':
+    const: 2
+
+  interrupt-controller:
+    description:
+      Identify that the PMIC is capable of behaving as an interrupt controller.
+
+  gpios:
+    maxItems: 1
+
+  regulators:
+    type: object
+
+    properties:
+      '#address-cells':
+        const: 1
+
+      '#size-cells':
+        const: 0
+
+    patternProperties:
+      '^ldo[0-9]+@[0-9a-f]$':
+        type: object
+
+        $ref: "/schemas/regulator/regulator.yaml#"
+
+        properties:
+          reg:
+            description: Enable register.
+
+          '#address-cells':
+            const: 1
+
+          '#size-cells':
+            const: 0
+
+          vsel-reg:
+            description: Voltage selector register.
+
+          enable-mask:
+            description: Bitmask used to enable the regulator.
+
+          voltage-table:
+            description: Table with the selector items for the voltage regulator.
+            minItems: 2
+            maxItems: 16
+
+          off-on-delay-us:
+            description: Time required for changing state to enabled in microseconds.
+
+          startup-delay-us:
+            description: Startup time in microseconds.
+
+          idle-mode-mask:
+            description: Bitmask used to put the regulator on idle mode.
+
+          eco-microamp:
+            description: Maximum current while on idle mode.
+
+        required:
+          - reg
+          - vsel-reg
+          - enable-mask
+          - voltage-table
+          - off-on-delay-us
+          - startup-delay-us
+
+required:
+  - compatible
+  - reg
+  - regulators
+
+examples:
+  - |
+    /* pmic properties */
+
+    pmic: pmic@0 {
+      compatible = "hisilicon,hi6421-spmi";
+      reg = <0 0>;
+
+      #interrupt-cells = <2>;
+      interrupt-controller;
+      gpios = <&gpio28 0 0>;
+
+      regulators {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ldo3: ldo3@16 {
+          reg = <0x16>;
+          vsel-reg = <0x51>;
+
+          regulator-name = "ldo3";
+          regulator-min-microvolt = <1500000>;
+          regulator-max-microvolt = <2000000>;
+          regulator-boot-on;
+
+          enable-mask = <0x01>;
+
+          voltage-table = <1500000>, <1550000>, <1600000>, <1650000>,
+                          <1700000>, <1725000>, <1750000>, <1775000>,
+                          <1800000>, <1825000>, <1850000>, <1875000>,
+                          <1900000>, <1925000>, <1950000>, <2000000>;
+          off-on-delay-us = <20000>;
+          startup-delay-us = <120>;
+        };
+
+        ldo4: ldo4@17 { /* 40 PIN */
+          reg = <0x17>;
+          vsel-reg = <0x52>;
+
+          regulator-name = "ldo4";
+          regulator-min-microvolt = <1725000>;
+          regulator-max-microvolt = <1900000>;
+          regulator-boot-on;
+
+          enable-mask = <0x01>;
+          idle-mode-mask = <0x10>;
+          eco-microamp = <10000>;
+
+          hi6421-vsel = <0x52 0x07>;
+          voltage-table = <1725000>, <1750000>, <1775000>, <1800000>,
+                          <1825000>, <1850000>, <1875000>, <1900000>;
+          off-on-delay-us = <20000>;
+          startup-delay-us = <120>;
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 14bc7b45ed50..450c7cbc6725 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7994,6 +7994,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
 F:	drivers/spmi/hisi-spmi-controller.c
 
+HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
+M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+F:	drivers/mfd/hi6421-spmi-pmic.c
+
 HISILICON STAGING DRIVERS FOR HIKEY 960/970
 M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
 L:	devel@driverdev.osuosl.org
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8b99a13669bf..c04c2f6be1d9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -509,6 +509,21 @@ config MFD_HI6421_PMIC
 	  menus in order to enable them.
 	  We communicate with the Hi6421 via memory-mapped I/O.
 
+config MFD_HI6421_SPMI
+	tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
+	depends on OF
+	depends on SPMI
+	select MFD_CORE
+	help
+	  Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
+	  multi-functions, such as regulators, RTC, codec, Coulomb counter,
+	  etc.
+
+	  This driver includes core APIs _only_. You have to select
+	  individual components like voltage regulators under corresponding
+	  menus in order to enable them.
+	  We communicate with the Hi6421v600 via a SPMI bus.
+
 config MFD_HI655X_PMIC
 	tristate "HiSilicon Hi655X series PMU/Codec IC"
 	depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1780019d2474..7744993c42bc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -233,6 +233,7 @@ obj-$(CONFIG_MFD_IPAQ_MICRO)	+= ipaq-micro.o
 obj-$(CONFIG_MFD_IQS62X)	+= iqs62x.o
 obj-$(CONFIG_MFD_MENF21BMC)	+= menf21bmc.o
 obj-$(CONFIG_MFD_HI6421_PMIC)	+= hi6421-pmic-core.o
+obj-$(CONFIG_MFD_HI6421_SPMI)	+= hi6421-spmi-pmic.o
 obj-$(CONFIG_MFD_HI655X_PMIC)   += hi655x-pmic.o
 obj-$(CONFIG_MFD_DLN2)		+= dln2.o
 obj-$(CONFIG_MFD_RT5033)	+= rt5033.o
diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
new file mode 100644
index 000000000000..64b30d263c8d
--- /dev/null
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for regulators in HISI PMIC IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* 8-bit register offset in PMIC */
+#define HISI_MASK_STATE			0xff
+
+#define HISI_IRQ_ARRAY			2
+#define HISI_IRQ_NUM			(HISI_IRQ_ARRAY * 8)
+
+#define SOC_PMIC_IRQ_MASK_0_ADDR	0x0202
+#define SOC_PMIC_IRQ0_ADDR		0x0212
+
+#define HISI_IRQ_KEY_NUM		0
+#define HISI_IRQ_KEY_VALUE		0xc0
+#define HISI_IRQ_KEY_DOWN		7
+#define HISI_IRQ_KEY_UP			6
+
+#define HISI_MASK_FIELD			0xFF
+#define HISI_BITS			8
+
+/*define the first group interrupt register number*/
+#define HISI_PMIC_FIRST_GROUP_INT_NUM	2
+
+static const struct mfd_cell hi6421v600_devs[] = {
+	{ .name = "hi6421v600-regulator", },
+};
+
+/*
+ * The PMIC register is only 8-bit.
+ * Hisilicon SoC use hardware to map PMIC register into SoC mapping.
+ * At here, we are accessing SoC register with 32-bit.
+ */
+int hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)
+{
+	struct spmi_device *pdev;
+	u8 read_value = 0;
+	u32 ret;
+
+	pdev = to_spmi_device(pmic->dev);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = spmi_ext_register_readl(pdev, reg, &read_value, 1);
+	if (ret) {
+		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
+		return ret;
+	}
+	return read_value;
+}
+EXPORT_SYMBOL(hi6421_spmi_pmic_read);
+
+int hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val)
+{
+	struct spmi_device *pdev;
+	u32 ret;
+
+	pdev = to_spmi_device(pmic->dev);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1);
+	if (ret)
+		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
+
+	return ret;
+}
+EXPORT_SYMBOL(hi6421_spmi_pmic_write);
+
+int hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg,
+			 u32 mask, u32 bits)
+{
+	unsigned long flags;
+	u32 data;
+	int ret;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hi6421_spmi_pmic_read(pmic, reg) & ~mask;
+	data |= mask & bits;
+	ret = hi6421_spmi_pmic_write(pmic, reg, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(hi6421_spmi_pmic_rmw);
+
+static irqreturn_t hi6421_spmi_irq_handler(int irq, void *data)
+{
+	struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)data;
+	unsigned long pending;
+	int i, offset;
+
+	for (i = 0; i < HISI_IRQ_ARRAY; i++) {
+		pending = hi6421_spmi_pmic_read(pmic, (i + SOC_PMIC_IRQ0_ADDR));
+		pending &= HISI_MASK_FIELD;
+		if (pending != 0)
+			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
+
+		hi6421_spmi_pmic_write(pmic, (i + SOC_PMIC_IRQ0_ADDR), pending);
+
+		/* solve powerkey order */
+		if ((i == HISI_IRQ_KEY_NUM) &&
+		    ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
+			generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_DOWN]);
+			generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_UP]);
+			pending &= (~HISI_IRQ_KEY_VALUE);
+		}
+
+		if (pending) {
+			for_each_set_bit(offset, &pending, HISI_BITS)
+				generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void hi6421_spmi_irq_mask(struct irq_data *d)
+{
+	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	u32 data, offset;
+	unsigned long flags;
+
+	offset = (irqd_to_hwirq(d) >> 3);
+	offset += SOC_PMIC_IRQ_MASK_0_ADDR;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hi6421_spmi_pmic_read(pmic, offset);
+	data |= (1 << (irqd_to_hwirq(d) & 0x07));
+	hi6421_spmi_pmic_write(pmic, offset, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static void hi6421_spmi_irq_unmask(struct irq_data *d)
+{
+	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	u32 data, offset;
+	unsigned long flags;
+
+	offset = (irqd_to_hwirq(d) >> 3);
+	offset += SOC_PMIC_IRQ_MASK_0_ADDR;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hi6421_spmi_pmic_read(pmic, offset);
+	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
+	hi6421_spmi_pmic_write(pmic, offset, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static struct irq_chip hi6421_spmi_pmu_irqchip = {
+	.name		= "hisi-irq",
+	.irq_mask	= hi6421_spmi_irq_mask,
+	.irq_unmask	= hi6421_spmi_irq_unmask,
+	.irq_disable	= hi6421_spmi_irq_mask,
+	.irq_enable	= hi6421_spmi_irq_unmask,
+};
+
+static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
+			       irq_hw_number_t hw)
+{
+	struct hi6421_spmi_pmic *pmic = d->host_data;
+
+	irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
+				      handle_simple_irq, "hisi");
+	irq_set_chip_data(virq, pmic);
+	irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+	return 0;
+}
+
+static const struct irq_domain_ops hi6421_spmi_domain_ops = {
+	.map	= hi6421_spmi_irq_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
+{
+	int i, pending;
+
+	for (i = 0 ; i < HISI_IRQ_ARRAY; i++)
+		hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ_MASK_0_ADDR + i,
+				       HISI_MASK_STATE);
+
+	for (i = 0 ; i < HISI_IRQ_ARRAY; i++) {
+		pending = hi6421_spmi_pmic_read(pmic, SOC_PMIC_IRQ0_ADDR + i);
+
+		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
+			 SOC_PMIC_IRQ0_ADDR + i, pending);
+		hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ0_ADDR + i,
+				       HISI_MASK_STATE);
+	}
+}
+
+static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct hi6421_spmi_pmic *pmic;
+	unsigned int virq;
+	int ret, i;
+
+	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	spin_lock_init(&pmic->lock);
+
+	pmic->dev = dev;
+
+	pmic->gpio = of_get_gpio(np, 0);
+	if (pmic->gpio < 0)
+		return pmic->gpio;
+
+	if (!gpio_is_valid(pmic->gpio))
+		return -EINVAL;
+
+	ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic");
+	if (ret < 0) {
+		dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
+		return ret;
+	}
+
+	pmic->irq = gpio_to_irq(pmic->gpio);
+
+	hi6421_spmi_pmic_irq_prc(pmic);
+
+	pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
+	if (!pmic->irqs)
+		goto irq_malloc;
+
+	pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
+					     &hi6421_spmi_domain_ops, pmic);
+	if (!pmic->domain) {
+		dev_err(dev, "failed irq domain add simple!\n");
+		ret = -ENODEV;
+		goto irq_malloc;
+	}
+
+	for (i = 0; i < HISI_IRQ_NUM; i++) {
+		virq = irq_create_mapping(pmic->domain, i);
+		if (!virq) {
+			dev_err(dev, "Failed mapping hwirq\n");
+			ret = -ENOSPC;
+			goto irq_malloc;
+		}
+		pmic->irqs[i] = virq;
+		dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n",
+			__func__, i, pmic->irqs[i]);
+	}
+
+	ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
+				   IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+				   "pmic", pmic);
+	if (ret < 0) {
+		dev_err(dev, "could not claim pmic IRQ: error %d\n", ret);
+		goto irq_malloc;
+	}
+
+	dev_set_drvdata(&pdev->dev, pmic);
+
+	/*
+	 * The logic below will rely that the pmic is already stored at
+	 * drvdata.
+	 */
+	dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n",
+		pdev->dev.of_node);
+	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				   hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
+				   NULL, 0, NULL);
+	if (!ret)
+		return 0;
+
+	dev_err(dev, "Failed to add child devices: %d\n", ret);
+
+irq_malloc:
+	free_irq(pmic->irq, pmic);
+
+	return ret;
+}
+
+static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
+{
+	struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
+
+	free_irq(pmic->irq, pmic);
+}
+
+static const struct of_device_id pmic_spmi_id_table[] = {
+	{ .compatible = "hisilicon,hi6421-spmi" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
+
+static struct spmi_driver hi6421_spmi_pmic_driver = {
+	.driver = {
+		.name	= "hi6421-spmi-pmic",
+		.of_match_table = pmic_spmi_id_table,
+	},
+	.probe	= hi6421_spmi_pmic_probe,
+	.remove	= hi6421_spmi_pmic_remove,
+};
+module_spmi_driver(hi6421_spmi_pmic_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index 69392e42cd0d..1afb8648a2c4 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,21 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-# to be placed at drivers/mfd
-config MFD_HI6421_SPMI
-	tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
-	depends on OF
-	depends on SPMI
-	select MFD_CORE
-	help
-	  Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
-	  multi-functions, such as regulators, RTC, codec, Coulomb counter,
-	  etc.
-
-	  This driver includes core APIs _only_. You have to select
-	  individual components like voltage regulators under corresponding
-	  menus in order to enable them.
-	  We communicate with the Hi6421v600 via a SPMI bus.
-
 # to be placed at drivers/regulator
 config REGULATOR_HI6421V600
 	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 347880fd378f..4d63184e6086 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,4 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_MFD_HI6421_SPMI)		+= hi6421-spmi-pmic.o
 obj-$(CONFIG_REGULATOR_HI6421V600)	+= hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
deleted file mode 100644
index 64b30d263c8d..000000000000
--- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
+++ /dev/null
@@ -1,342 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Device driver for regulators in HISI PMIC IC
- *
- * Copyright (c) 2013 Linaro Ltd.
- * Copyright (c) 2011 Hisilicon.
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/hi6421-spmi-pmic.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-/* 8-bit register offset in PMIC */
-#define HISI_MASK_STATE			0xff
-
-#define HISI_IRQ_ARRAY			2
-#define HISI_IRQ_NUM			(HISI_IRQ_ARRAY * 8)
-
-#define SOC_PMIC_IRQ_MASK_0_ADDR	0x0202
-#define SOC_PMIC_IRQ0_ADDR		0x0212
-
-#define HISI_IRQ_KEY_NUM		0
-#define HISI_IRQ_KEY_VALUE		0xc0
-#define HISI_IRQ_KEY_DOWN		7
-#define HISI_IRQ_KEY_UP			6
-
-#define HISI_MASK_FIELD			0xFF
-#define HISI_BITS			8
-
-/*define the first group interrupt register number*/
-#define HISI_PMIC_FIRST_GROUP_INT_NUM	2
-
-static const struct mfd_cell hi6421v600_devs[] = {
-	{ .name = "hi6421v600-regulator", },
-};
-
-/*
- * The PMIC register is only 8-bit.
- * Hisilicon SoC use hardware to map PMIC register into SoC mapping.
- * At here, we are accessing SoC register with 32-bit.
- */
-int hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)
-{
-	struct spmi_device *pdev;
-	u8 read_value = 0;
-	u32 ret;
-
-	pdev = to_spmi_device(pmic->dev);
-	if (!pdev) {
-		pr_err("%s: pdev get failed!\n", __func__);
-		return -ENODEV;
-	}
-
-	ret = spmi_ext_register_readl(pdev, reg, &read_value, 1);
-	if (ret) {
-		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
-		return ret;
-	}
-	return read_value;
-}
-EXPORT_SYMBOL(hi6421_spmi_pmic_read);
-
-int hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val)
-{
-	struct spmi_device *pdev;
-	u32 ret;
-
-	pdev = to_spmi_device(pmic->dev);
-	if (!pdev) {
-		pr_err("%s: pdev get failed!\n", __func__);
-		return -ENODEV;
-	}
-
-	ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1);
-	if (ret)
-		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
-
-	return ret;
-}
-EXPORT_SYMBOL(hi6421_spmi_pmic_write);
-
-int hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg,
-			 u32 mask, u32 bits)
-{
-	unsigned long flags;
-	u32 data;
-	int ret;
-
-	spin_lock_irqsave(&pmic->lock, flags);
-	data = hi6421_spmi_pmic_read(pmic, reg) & ~mask;
-	data |= mask & bits;
-	ret = hi6421_spmi_pmic_write(pmic, reg, data);
-	spin_unlock_irqrestore(&pmic->lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(hi6421_spmi_pmic_rmw);
-
-static irqreturn_t hi6421_spmi_irq_handler(int irq, void *data)
-{
-	struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)data;
-	unsigned long pending;
-	int i, offset;
-
-	for (i = 0; i < HISI_IRQ_ARRAY; i++) {
-		pending = hi6421_spmi_pmic_read(pmic, (i + SOC_PMIC_IRQ0_ADDR));
-		pending &= HISI_MASK_FIELD;
-		if (pending != 0)
-			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
-
-		hi6421_spmi_pmic_write(pmic, (i + SOC_PMIC_IRQ0_ADDR), pending);
-
-		/* solve powerkey order */
-		if ((i == HISI_IRQ_KEY_NUM) &&
-		    ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
-			generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_DOWN]);
-			generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_UP]);
-			pending &= (~HISI_IRQ_KEY_VALUE);
-		}
-
-		if (pending) {
-			for_each_set_bit(offset, &pending, HISI_BITS)
-				generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]);
-		}
-	}
-
-	return IRQ_HANDLED;
-}
-
-static void hi6421_spmi_irq_mask(struct irq_data *d)
-{
-	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
-	u32 data, offset;
-	unsigned long flags;
-
-	offset = (irqd_to_hwirq(d) >> 3);
-	offset += SOC_PMIC_IRQ_MASK_0_ADDR;
-
-	spin_lock_irqsave(&pmic->lock, flags);
-	data = hi6421_spmi_pmic_read(pmic, offset);
-	data |= (1 << (irqd_to_hwirq(d) & 0x07));
-	hi6421_spmi_pmic_write(pmic, offset, data);
-	spin_unlock_irqrestore(&pmic->lock, flags);
-}
-
-static void hi6421_spmi_irq_unmask(struct irq_data *d)
-{
-	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
-	u32 data, offset;
-	unsigned long flags;
-
-	offset = (irqd_to_hwirq(d) >> 3);
-	offset += SOC_PMIC_IRQ_MASK_0_ADDR;
-
-	spin_lock_irqsave(&pmic->lock, flags);
-	data = hi6421_spmi_pmic_read(pmic, offset);
-	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
-	hi6421_spmi_pmic_write(pmic, offset, data);
-	spin_unlock_irqrestore(&pmic->lock, flags);
-}
-
-static struct irq_chip hi6421_spmi_pmu_irqchip = {
-	.name		= "hisi-irq",
-	.irq_mask	= hi6421_spmi_irq_mask,
-	.irq_unmask	= hi6421_spmi_irq_unmask,
-	.irq_disable	= hi6421_spmi_irq_mask,
-	.irq_enable	= hi6421_spmi_irq_unmask,
-};
-
-static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
-			       irq_hw_number_t hw)
-{
-	struct hi6421_spmi_pmic *pmic = d->host_data;
-
-	irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
-				      handle_simple_irq, "hisi");
-	irq_set_chip_data(virq, pmic);
-	irq_set_irq_type(virq, IRQ_TYPE_NONE);
-
-	return 0;
-}
-
-static const struct irq_domain_ops hi6421_spmi_domain_ops = {
-	.map	= hi6421_spmi_irq_map,
-	.xlate	= irq_domain_xlate_twocell,
-};
-
-static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
-{
-	int i, pending;
-
-	for (i = 0 ; i < HISI_IRQ_ARRAY; i++)
-		hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ_MASK_0_ADDR + i,
-				       HISI_MASK_STATE);
-
-	for (i = 0 ; i < HISI_IRQ_ARRAY; i++) {
-		pending = hi6421_spmi_pmic_read(pmic, SOC_PMIC_IRQ0_ADDR + i);
-
-		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
-			 SOC_PMIC_IRQ0_ADDR + i, pending);
-		hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ0_ADDR + i,
-				       HISI_MASK_STATE);
-	}
-}
-
-static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	struct hi6421_spmi_pmic *pmic;
-	unsigned int virq;
-	int ret, i;
-
-	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
-	if (!pmic)
-		return -ENOMEM;
-
-	spin_lock_init(&pmic->lock);
-
-	pmic->dev = dev;
-
-	pmic->gpio = of_get_gpio(np, 0);
-	if (pmic->gpio < 0)
-		return pmic->gpio;
-
-	if (!gpio_is_valid(pmic->gpio))
-		return -EINVAL;
-
-	ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic");
-	if (ret < 0) {
-		dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
-		return ret;
-	}
-
-	pmic->irq = gpio_to_irq(pmic->gpio);
-
-	hi6421_spmi_pmic_irq_prc(pmic);
-
-	pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
-	if (!pmic->irqs)
-		goto irq_malloc;
-
-	pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
-					     &hi6421_spmi_domain_ops, pmic);
-	if (!pmic->domain) {
-		dev_err(dev, "failed irq domain add simple!\n");
-		ret = -ENODEV;
-		goto irq_malloc;
-	}
-
-	for (i = 0; i < HISI_IRQ_NUM; i++) {
-		virq = irq_create_mapping(pmic->domain, i);
-		if (!virq) {
-			dev_err(dev, "Failed mapping hwirq\n");
-			ret = -ENOSPC;
-			goto irq_malloc;
-		}
-		pmic->irqs[i] = virq;
-		dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n",
-			__func__, i, pmic->irqs[i]);
-	}
-
-	ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
-				   IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
-				   "pmic", pmic);
-	if (ret < 0) {
-		dev_err(dev, "could not claim pmic IRQ: error %d\n", ret);
-		goto irq_malloc;
-	}
-
-	dev_set_drvdata(&pdev->dev, pmic);
-
-	/*
-	 * The logic below will rely that the pmic is already stored at
-	 * drvdata.
-	 */
-	dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n",
-		pdev->dev.of_node);
-	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
-				   hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
-				   NULL, 0, NULL);
-	if (!ret)
-		return 0;
-
-	dev_err(dev, "Failed to add child devices: %d\n", ret);
-
-irq_malloc:
-	free_irq(pmic->irq, pmic);
-
-	return ret;
-}
-
-static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
-{
-	struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
-
-	free_irq(pmic->irq, pmic);
-}
-
-static const struct of_device_id pmic_spmi_id_table[] = {
-	{ .compatible = "hisilicon,hi6421-spmi" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
-
-static struct spmi_driver hi6421_spmi_pmic_driver = {
-	.driver = {
-		.name	= "hi6421-spmi-pmic",
-		.of_match_table = pmic_spmi_id_table,
-	},
-	.probe	= hi6421_spmi_pmic_probe,
-	.remove	= hi6421_spmi_pmic_remove,
-};
-module_spmi_driver(hi6421_spmi_pmic_driver);
-
-MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
deleted file mode 100644
index 80e74c261e05..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
+++ /dev/null
@@ -1,159 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: HiSilicon 6421v600 SPMI PMIC
-
-maintainers:
-  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |
-  HiSilicon 6421v600 should be connected inside a MIPI System Power Management
-  (SPMI) bus. It provides interrupts and power supply.
-
-  The GPIO and interrupt settings are represented as part of the top-level PMIC
-  node.
-
-  The SPMI controller part is provided by
-  drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
-
-properties:
-  $nodename:
-    pattern: "pmic@[0-9a-f]"
-
-  compatible:
-    const: hisilicon,hi6421v600-spmi
-
-  reg:
-    maxItems: 1
-
-  '#interrupt-cells':
-    const: 2
-
-  interrupt-controller:
-    description:
-      Identify that the PMIC is capable of behaving as an interrupt controller.
-
-  gpios:
-    maxItems: 1
-
-  regulators:
-    type: object
-
-    properties:
-      '#address-cells':
-        const: 1
-
-      '#size-cells':
-        const: 0
-
-    patternProperties:
-      '^ldo[0-9]+@[0-9a-f]$':
-        type: object
-
-        $ref: "/schemas/regulator/regulator.yaml#"
-
-        properties:
-          reg:
-            description: Enable register.
-
-          '#address-cells':
-            const: 1
-
-          '#size-cells':
-            const: 0
-
-          vsel-reg:
-            description: Voltage selector register.
-
-          enable-mask:
-            description: Bitmask used to enable the regulator.
-
-          voltage-table:
-            description: Table with the selector items for the voltage regulator.
-            minItems: 2
-            maxItems: 16
-
-          off-on-delay-us:
-            description: Time required for changing state to enabled in microseconds.
-
-          startup-delay-us:
-            description: Startup time in microseconds.
-
-          idle-mode-mask:
-            description: Bitmask used to put the regulator on idle mode.
-
-          eco-microamp:
-            description: Maximum current while on idle mode.
-
-        required:
-          - reg
-          - vsel-reg
-          - enable-mask
-          - voltage-table
-          - off-on-delay-us
-          - startup-delay-us
-
-required:
-  - compatible
-  - reg
-  - regulators
-
-examples:
-  - |
-    /* pmic properties */
-
-    pmic: pmic@0 {
-      compatible = "hisilicon,hi6421-spmi";
-      reg = <0 0>;
-
-      #interrupt-cells = <2>;
-      interrupt-controller;
-      gpios = <&gpio28 0 0>;
-
-      regulators {
-        #address-cells = <1>;
-        #size-cells = <0>;
-
-        ldo3: ldo3@16 {
-          reg = <0x16>;
-          vsel-reg = <0x51>;
-
-          regulator-name = "ldo3";
-          regulator-min-microvolt = <1500000>;
-          regulator-max-microvolt = <2000000>;
-          regulator-boot-on;
-
-          enable-mask = <0x01>;
-
-          voltage-table = <1500000>, <1550000>, <1600000>, <1650000>,
-                          <1700000>, <1725000>, <1750000>, <1775000>,
-                          <1800000>, <1825000>, <1850000>, <1875000>,
-                          <1900000>, <1925000>, <1950000>, <2000000>;
-          off-on-delay-us = <20000>;
-          startup-delay-us = <120>;
-        };
-
-        ldo4: ldo4@17 { /* 40 PIN */
-          reg = <0x17>;
-          vsel-reg = <0x52>;
-
-          regulator-name = "ldo4";
-          regulator-min-microvolt = <1725000>;
-          regulator-max-microvolt = <1900000>;
-          regulator-boot-on;
-
-          enable-mask = <0x01>;
-          idle-mode-mask = <0x10>;
-          eco-microamp = <10000>;
-
-          hi6421-vsel = <0x52 0x07>;
-          voltage-table = <1725000>, <1750000>, <1775000>, <1800000>,
-                          <1825000>, <1850000>, <1875000>, <1900000>;
-          off-on-delay-us = <20000>;
-          startup-delay-us = <120>;
-        };
-      };
-    };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2020-11-16 12:59 ` [PATCH 3/8] mfd: " Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 18:38   ` Mark Brown
  2020-11-16 12:59 ` [PATCH 5/8] arm64: dts: hisilicon: hi3670.dtsi: add I2C settings Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Mark Brown
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Greg Kroah-Hartman, Liam Girdwood,
	Mayulong, YueHaibing, devel, linux-kernel

This driver is ready for mainstream. Move it out of staging.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 MAINTAINERS                                   |   7 +-
 drivers/regulator/Kconfig                     |   9 +
 drivers/regulator/Makefile                    |   1 +
 drivers/regulator/hi6421v600-regulator.c      | 478 ++++++++++++++++++
 drivers/staging/Kconfig                       |   2 -
 drivers/staging/Makefile                      |   1 -
 drivers/staging/hikey9xx/Kconfig              |  11 -
 drivers/staging/hikey9xx/Makefile             |   3 -
 drivers/staging/hikey9xx/TODO                 |   5 -
 .../staging/hikey9xx/hi6421v600-regulator.c   | 478 ------------------
 10 files changed, 489 insertions(+), 506 deletions(-)
 create mode 100644 drivers/regulator/hi6421v600-regulator.c
 delete mode 100644 drivers/staging/hikey9xx/Kconfig
 delete mode 100644 drivers/staging/hikey9xx/Makefile
 delete mode 100644 drivers/staging/hikey9xx/TODO
 delete mode 100644 drivers/staging/hikey9xx/hi6421v600-regulator.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 450c7cbc6725..aa68aee9e684 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8000,12 +8000,7 @@ L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 F:	drivers/mfd/hi6421-spmi-pmic.c
-
-HISILICON STAGING DRIVERS FOR HIKEY 960/970
-M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-L:	devel@driverdev.osuosl.org
-S:	Maintained
-F:	drivers/staging/hikey9xx/
+F:	drivers/regulator/hi6421v600-regulator.c
 
 HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
 M:	Zaibo Xu <xuzaibo@huawei.com>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 020a00d6696b..08d302c87fa0 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -394,6 +394,15 @@ config REGULATOR_HI655X
 	  This driver provides support for the voltage regulators of the
 	  Hisilicon Hi655x PMIC device.
 
+config REGULATOR_HI6421V600
+	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
+	depends on MFD_HI6421_SPMI && OF
+	depends on REGULATOR
+	help
+	  This driver provides support for the voltage regulators on
+	  HiSilicon Hi6421v600 PMU / Codec IC.
+	  This is used on Kirin 3670 boards, like HiKey 970.
+
 config REGULATOR_ISL9305
 	tristate "Intersil ISL9305 regulator"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 6ebae516258e..45d1883de54b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o
 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
 obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o
+obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
 obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
new file mode 100644
index 000000000000..614b03c9ddfb
--- /dev/null
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for regulators in Hisi IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ *
+ * Guodong Xu <guodong.xu@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+
+#define rdev_dbg(rdev, fmt, arg...)	\
+		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)
+
+struct hi6421v600_regulator {
+	struct regulator_desc rdesc;
+	struct hi6421_spmi_pmic *pmic;
+	u32 eco_mode_mask, eco_uA;
+};
+
+static DEFINE_MUTEX(enable_mutex);
+
+/*
+ * helper function to ensure when it returns it is at least 'delay_us'
+ * microseconds after 'since'.
+ */
+
+static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+	u32 reg_val;
+
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
+
+	rdev_dbg(rdev,
+		 "enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
+		 rdev->desc->enable_reg,
+		 reg_val, (reg_val & rdev->desc->enable_mask));
+
+	return ((reg_val & rdev->desc->enable_mask) != 0);
+}
+
+static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+
+	/* cannot enable more than one regulator at one time */
+	mutex_lock(&enable_mutex);
+	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
+		     HISI_REGS_ENA_PROTECT_TIME + 1000);
+
+	/* set enable register */
+	rdev_dbg(rdev,
+		 "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n",
+		 rdev->desc->off_on_delay, rdev->desc->enable_reg,
+		 rdev->desc->enable_mask);
+
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
+			     rdev->desc->enable_mask,
+			     rdev->desc->enable_mask);
+
+	mutex_unlock(&enable_mutex);
+
+	return 0;
+}
+
+static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+
+	/* set enable register to 0 */
+	rdev_dbg(rdev, "enable_reg=0x%x, enable_mask=0x%x\n",
+		 rdev->desc->enable_reg, rdev->desc->enable_mask);
+
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
+			     rdev->desc->enable_mask, 0);
+
+	return 0;
+}
+
+static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+	u32 reg_val, selector;
+
+	/* get voltage selector */
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->vsel_reg);
+
+	selector = (reg_val & rdev->desc->vsel_mask) >>	(ffs(rdev->desc->vsel_mask) - 1);
+
+	rdev_dbg(rdev,
+		 "vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n",
+		 rdev->desc->vsel_reg, reg_val, selector,
+		rdev->desc->ops->list_voltage(rdev, selector) / 1000);
+
+	return selector;
+}
+
+static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev,
+						 unsigned int selector)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+	u32 reg_val;
+
+	if (unlikely(selector >= rdev->desc->n_voltages))
+		return -EINVAL;
+
+	reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1);
+
+	/* set voltage selector */
+	rdev_dbg(rdev,
+		 "vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n",
+		 rdev->desc->vsel_reg, rdev->desc->vsel_mask, reg_val,
+		 rdev->desc->ops->list_voltage(rdev, selector) / 1000);
+
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg,
+			     rdev->desc->vsel_mask, reg_val);
+
+	return 0;
+}
+
+static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+	unsigned int mode;
+	u32 reg_val;
+
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
+
+	if (reg_val & sreg->eco_mode_mask)
+		mode = REGULATOR_MODE_IDLE;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	rdev_dbg(rdev,
+		 "enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n",
+		 rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val,
+		 mode == REGULATOR_MODE_IDLE ? "idle" : "normal");
+
+	return mode;
+}
+
+static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
+					  unsigned int mode)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+	u32 val;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	case REGULATOR_MODE_IDLE:
+		val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set mode */
+	rdev_dbg(rdev, "enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
+		 rdev->desc->enable_reg, sreg->eco_mode_mask, val);
+
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
+			     sreg->eco_mode_mask, val);
+
+	return 0;
+}
+
+static unsigned int
+hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
+				       int input_uV, int output_uV,
+				       int load_uA)
+{
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+
+	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA))
+		return REGULATOR_MODE_NORMAL;
+
+	return REGULATOR_MODE_IDLE;
+}
+
+static int hi6421_spmi_dt_parse(struct platform_device *pdev,
+				struct hi6421v600_regulator *sreg,
+			 struct regulator_desc *rdesc)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	unsigned int *v_table;
+	int ret;
+
+	ret = of_property_read_u32(np, "reg", &rdesc->enable_reg);
+	if (ret) {
+		dev_err(dev, "missing reg property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);
+	if (ret) {
+		dev_err(dev, "missing vsel-reg property\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "enable-mask", &rdesc->enable_mask);
+	if (ret) {
+		dev_err(dev, "missing enable-mask property\n");
+		return ret;
+	}
+
+	/*
+	 * Not all regulators work on idle mode
+	 */
+	ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask);
+	if (ret) {
+		dev_dbg(dev, "LDO doesn't support economy mode.\n");
+		sreg->eco_mode_mask = 0;
+		sreg->eco_uA = 0;
+	} else {
+		ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA);
+		if (ret) {
+			dev_err(dev, "missing eco-microamp property\n");
+			return ret;
+		}
+	}
+
+	/* parse .off-on-delay */
+	ret = of_property_read_u32(np, "off-on-delay-us",
+				   &rdesc->off_on_delay);
+	if (ret) {
+		dev_err(dev, "missing off-on-delay-us property\n");
+		return ret;
+	}
+
+	/* parse .enable_time */
+	ret = of_property_read_u32(np, "startup-delay-us",
+				   &rdesc->enable_time);
+	if (ret) {
+		dev_err(dev, "missing startup-delay-us property\n");
+		return ret;
+	}
+
+	/* FIXME: are there a better value for this? */
+	rdesc->ramp_delay = rdesc->enable_time;
+
+	/* parse volt_table */
+
+	rdesc->n_voltages = of_property_count_u32_elems(np, "voltage-table");
+
+	v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
+			       GFP_KERNEL);
+	if (unlikely(!v_table))
+		return  -ENOMEM;
+	rdesc->volt_table = v_table;
+
+	ret = of_property_read_u32_array(np, "voltage-table",
+					 v_table, rdesc->n_voltages);
+	if (ret) {
+		dev_err(dev, "missing voltage-table property\n");
+		return ret;
+	}
+
+	/*
+	 * Instead of explicitly requiring a mask for the voltage selector,
+	 * as they all start from bit zero (at least on the known LDOs),
+	 * just use the number of voltages at the voltage table, getting the
+	 * minimal mask that would pick everything.
+	 */
+	rdesc->vsel_mask = (1 << (fls(rdesc->n_voltages) - 1)) - 1;
+
+	dev_dbg(dev, "voltage selector settings: reg: 0x%x, mask: 0x%x\n",
+		rdesc->vsel_reg, rdesc->vsel_mask);
+
+	return 0;
+}
+
+static const struct regulator_ops hi6421_spmi_ldo_rops = {
+	.is_enabled = hi6421_spmi_regulator_is_enabled,
+	.enable = hi6421_spmi_regulator_enable,
+	.disable = hi6421_spmi_regulator_disable,
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.get_voltage_sel = hi6421_spmi_regulator_get_voltage_sel,
+	.set_voltage_sel = hi6421_spmi_regulator_set_voltage_sel,
+	.get_mode = hi6421_spmi_regulator_get_mode,
+	.set_mode = hi6421_spmi_regulator_set_mode,
+	.get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode,
+};
+
+static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
+					   struct device_node *np,
+					   struct hi6421_spmi_pmic *pmic)
+{
+	struct regulation_constraints *constraint;
+	struct regulator_init_data *initdata;
+	struct regulator_config config = { };
+	struct hi6421v600_regulator *sreg;
+	struct device *dev = &pdev->dev;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	const char *supplyname;
+	int ret;
+
+	initdata = of_get_regulator_init_data(dev, np, NULL);
+	if (!initdata) {
+		dev_err(dev, "failed to get regulator data\n");
+		return -EINVAL;
+	}
+
+	sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
+	if (!sreg)
+		return -ENOMEM;
+
+	sreg->pmic = pmic;
+	rdesc = &sreg->rdesc;
+
+	rdesc->name = initdata->constraints.name;
+	rdesc->ops = &hi6421_spmi_ldo_rops;
+	rdesc->type = REGULATOR_VOLTAGE;
+	rdesc->min_uV = initdata->constraints.min_uV;
+
+	supplyname = of_get_property(np, "supply_name", NULL);
+	if (supplyname)
+		initdata->supply_regulator = supplyname;
+
+	/* parse device tree data for regulator specific */
+	ret = hi6421_spmi_dt_parse(pdev, sreg, rdesc);
+	if (ret)
+		return ret;
+
+	/* hisi regulator supports two modes */
+	constraint = &initdata->constraints;
+
+	constraint->valid_modes_mask = REGULATOR_MODE_NORMAL;
+	if (sreg->eco_mode_mask) {
+		constraint->valid_modes_mask |= REGULATOR_MODE_IDLE;
+		constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE;
+	}
+
+	config.dev = &pdev->dev;
+	config.init_data = initdata;
+	config.driver_data = sreg;
+	config.of_node = pdev->dev.of_node;
+
+	/* register regulator */
+	rdev = regulator_register(rdesc, &config);
+	if (IS_ERR(rdev)) {
+		dev_err(dev, "failed to register %s\n",
+			rdesc->name);
+		return PTR_ERR(rdev);
+	}
+
+	rdev_dbg(rdev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
+		 constraint->valid_modes_mask, constraint->valid_ops_mask);
+
+	dev_set_drvdata(dev, rdev);
+
+	return 0;
+}
+
+static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
+{
+	struct device *pmic_dev = pdev->dev.parent;
+	struct device_node *np = pmic_dev->of_node;
+	struct device_node *regulators, *child;
+	struct platform_device *new_pdev;
+	struct hi6421_spmi_pmic *pmic;
+	int ret;
+
+	/*
+	 * This driver is meant to be called by hi6421-spmi-core,
+	 * which should first set drvdata. If this doesn't happen, hit
+	 * a warn on and return.
+	 */
+	pmic = dev_get_drvdata(pmic_dev);
+	if (WARN_ON(!pmic))
+		return -ENODEV;
+
+	regulators = of_get_child_by_name(np, "regulators");
+	if (!regulators) {
+		dev_err(&pdev->dev, "regulator node not found\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Parse all LDO regulator nodes
+	 */
+	for_each_child_of_node(regulators, child) {
+		dev_dbg(&pdev->dev, "adding child %pOF\n", child);
+
+		new_pdev = platform_device_alloc(child->name, -1);
+		new_pdev->dev.parent = pmic_dev;
+		new_pdev->dev.of_node = of_node_get(child);
+
+		ret = platform_device_add(new_pdev);
+		if (ret < 0) {
+			platform_device_put(new_pdev);
+			continue;
+		}
+
+		ret = hi6421_spmi_regulator_probe_ldo(new_pdev, child, pmic);
+		if (ret < 0)
+			platform_device_put(new_pdev);
+	}
+
+	of_node_put(regulators);
+
+	return 0;
+}
+
+static int hi6421_spmi_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+
+	if (rdev->desc->volt_table)
+		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
+
+	kfree(sreg);
+
+	return 0;
+}
+
+static const struct platform_device_id hi6421v600_regulator_table[] = {
+	{ .name = "hi6421v600-regulator" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, hi6421v600_regulator_table);
+
+static struct platform_driver hi6421v600_regulator_driver = {
+	.id_table = hi6421v600_regulator_table,
+	.driver = {
+		.name	= "hi6421v600-regulator",
+	},
+	.probe	= hi6421_spmi_regulator_probe,
+	.remove	= hi6421_spmi_regulator_remove,
+};
+module_platform_driver(hi6421v600_regulator_driver);
+
+MODULE_DESCRIPTION("Hi6421v600 regulator driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 2d0310448eba..e6c831c6cccc 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -116,6 +116,4 @@ source "drivers/staging/qlge/Kconfig"
 
 source "drivers/staging/wfx/Kconfig"
 
-source "drivers/staging/hikey9xx/Kconfig"
-
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 757a892ab5b9..a3b1fd0622f9 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -48,4 +48,3 @@ obj-$(CONFIG_FIELDBUS_DEV)     += fieldbus/
 obj-$(CONFIG_KPC2000)		+= kpc2000/
 obj-$(CONFIG_QLGE)		+= qlge/
 obj-$(CONFIG_WFX)		+= wfx/
-obj-y				+= hikey9xx/
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
deleted file mode 100644
index 1afb8648a2c4..000000000000
--- a/drivers/staging/hikey9xx/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# to be placed at drivers/regulator
-config REGULATOR_HI6421V600
-	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
-	depends on MFD_HI6421_SPMI && OF
-	depends on REGULATOR
-	help
-	  This driver provides support for the voltage regulators on
-	  HiSilicon Hi6421v600 PMU / Codec IC.
-	  This is used on Kirin 3670 boards, like HiKey 970.
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
deleted file mode 100644
index 4d63184e6086..000000000000
--- a/drivers/staging/hikey9xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_REGULATOR_HI6421V600)	+= hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/TODO b/drivers/staging/hikey9xx/TODO
deleted file mode 100644
index 65e7996a3066..000000000000
--- a/drivers/staging/hikey9xx/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-ToDo list:
-
-- Port other drivers needed by Hikey 960/970;
-- Test drivers on Hikey 960;
-- Validate device tree bindings.
diff --git a/drivers/staging/hikey9xx/hi6421v600-regulator.c b/drivers/staging/hikey9xx/hi6421v600-regulator.c
deleted file mode 100644
index 614b03c9ddfb..000000000000
--- a/drivers/staging/hikey9xx/hi6421v600-regulator.c
+++ /dev/null
@@ -1,478 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Device driver for regulators in Hisi IC
- *
- * Copyright (c) 2013 Linaro Ltd.
- * Copyright (c) 2011 Hisilicon.
- *
- * Guodong Xu <guodong.xu@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mfd/hi6421-spmi-pmic.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-#include <linux/time.h>
-#include <linux/uaccess.h>
-
-#define rdev_dbg(rdev, fmt, arg...)	\
-		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)
-
-struct hi6421v600_regulator {
-	struct regulator_desc rdesc;
-	struct hi6421_spmi_pmic *pmic;
-	u32 eco_mode_mask, eco_uA;
-};
-
-static DEFINE_MUTEX(enable_mutex);
-
-/*
- * helper function to ensure when it returns it is at least 'delay_us'
- * microseconds after 'since'.
- */
-
-static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-	u32 reg_val;
-
-	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
-
-	rdev_dbg(rdev,
-		 "enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
-		 rdev->desc->enable_reg,
-		 reg_val, (reg_val & rdev->desc->enable_mask));
-
-	return ((reg_val & rdev->desc->enable_mask) != 0);
-}
-
-static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-
-	/* cannot enable more than one regulator at one time */
-	mutex_lock(&enable_mutex);
-	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
-		     HISI_REGS_ENA_PROTECT_TIME + 1000);
-
-	/* set enable register */
-	rdev_dbg(rdev,
-		 "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n",
-		 rdev->desc->off_on_delay, rdev->desc->enable_reg,
-		 rdev->desc->enable_mask);
-
-	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
-			     rdev->desc->enable_mask,
-			     rdev->desc->enable_mask);
-
-	mutex_unlock(&enable_mutex);
-
-	return 0;
-}
-
-static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-
-	/* set enable register to 0 */
-	rdev_dbg(rdev, "enable_reg=0x%x, enable_mask=0x%x\n",
-		 rdev->desc->enable_reg, rdev->desc->enable_mask);
-
-	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
-			     rdev->desc->enable_mask, 0);
-
-	return 0;
-}
-
-static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-	u32 reg_val, selector;
-
-	/* get voltage selector */
-	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->vsel_reg);
-
-	selector = (reg_val & rdev->desc->vsel_mask) >>	(ffs(rdev->desc->vsel_mask) - 1);
-
-	rdev_dbg(rdev,
-		 "vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n",
-		 rdev->desc->vsel_reg, reg_val, selector,
-		rdev->desc->ops->list_voltage(rdev, selector) / 1000);
-
-	return selector;
-}
-
-static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev,
-						 unsigned int selector)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-	u32 reg_val;
-
-	if (unlikely(selector >= rdev->desc->n_voltages))
-		return -EINVAL;
-
-	reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1);
-
-	/* set voltage selector */
-	rdev_dbg(rdev,
-		 "vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n",
-		 rdev->desc->vsel_reg, rdev->desc->vsel_mask, reg_val,
-		 rdev->desc->ops->list_voltage(rdev, selector) / 1000);
-
-	hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg,
-			     rdev->desc->vsel_mask, reg_val);
-
-	return 0;
-}
-
-static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-	unsigned int mode;
-	u32 reg_val;
-
-	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
-
-	if (reg_val & sreg->eco_mode_mask)
-		mode = REGULATOR_MODE_IDLE;
-	else
-		mode = REGULATOR_MODE_NORMAL;
-
-	rdev_dbg(rdev,
-		 "enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n",
-		 rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val,
-		 mode == REGULATOR_MODE_IDLE ? "idle" : "normal");
-
-	return mode;
-}
-
-static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
-					  unsigned int mode)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hi6421_spmi_pmic *pmic = sreg->pmic;
-	u32 val;
-
-	switch (mode) {
-	case REGULATOR_MODE_NORMAL:
-		val = 0;
-		break;
-	case REGULATOR_MODE_IDLE:
-		val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* set mode */
-	rdev_dbg(rdev, "enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
-		 rdev->desc->enable_reg, sreg->eco_mode_mask, val);
-
-	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
-			     sreg->eco_mode_mask, val);
-
-	return 0;
-}
-
-static unsigned int
-hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
-				       int input_uV, int output_uV,
-				       int load_uA)
-{
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-
-	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA))
-		return REGULATOR_MODE_NORMAL;
-
-	return REGULATOR_MODE_IDLE;
-}
-
-static int hi6421_spmi_dt_parse(struct platform_device *pdev,
-				struct hi6421v600_regulator *sreg,
-			 struct regulator_desc *rdesc)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	unsigned int *v_table;
-	int ret;
-
-	ret = of_property_read_u32(np, "reg", &rdesc->enable_reg);
-	if (ret) {
-		dev_err(dev, "missing reg property\n");
-		return ret;
-	}
-
-	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);
-	if (ret) {
-		dev_err(dev, "missing vsel-reg property\n");
-		return ret;
-	}
-
-	ret = of_property_read_u32(np, "enable-mask", &rdesc->enable_mask);
-	if (ret) {
-		dev_err(dev, "missing enable-mask property\n");
-		return ret;
-	}
-
-	/*
-	 * Not all regulators work on idle mode
-	 */
-	ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask);
-	if (ret) {
-		dev_dbg(dev, "LDO doesn't support economy mode.\n");
-		sreg->eco_mode_mask = 0;
-		sreg->eco_uA = 0;
-	} else {
-		ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA);
-		if (ret) {
-			dev_err(dev, "missing eco-microamp property\n");
-			return ret;
-		}
-	}
-
-	/* parse .off-on-delay */
-	ret = of_property_read_u32(np, "off-on-delay-us",
-				   &rdesc->off_on_delay);
-	if (ret) {
-		dev_err(dev, "missing off-on-delay-us property\n");
-		return ret;
-	}
-
-	/* parse .enable_time */
-	ret = of_property_read_u32(np, "startup-delay-us",
-				   &rdesc->enable_time);
-	if (ret) {
-		dev_err(dev, "missing startup-delay-us property\n");
-		return ret;
-	}
-
-	/* FIXME: are there a better value for this? */
-	rdesc->ramp_delay = rdesc->enable_time;
-
-	/* parse volt_table */
-
-	rdesc->n_voltages = of_property_count_u32_elems(np, "voltage-table");
-
-	v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
-			       GFP_KERNEL);
-	if (unlikely(!v_table))
-		return  -ENOMEM;
-	rdesc->volt_table = v_table;
-
-	ret = of_property_read_u32_array(np, "voltage-table",
-					 v_table, rdesc->n_voltages);
-	if (ret) {
-		dev_err(dev, "missing voltage-table property\n");
-		return ret;
-	}
-
-	/*
-	 * Instead of explicitly requiring a mask for the voltage selector,
-	 * as they all start from bit zero (at least on the known LDOs),
-	 * just use the number of voltages at the voltage table, getting the
-	 * minimal mask that would pick everything.
-	 */
-	rdesc->vsel_mask = (1 << (fls(rdesc->n_voltages) - 1)) - 1;
-
-	dev_dbg(dev, "voltage selector settings: reg: 0x%x, mask: 0x%x\n",
-		rdesc->vsel_reg, rdesc->vsel_mask);
-
-	return 0;
-}
-
-static const struct regulator_ops hi6421_spmi_ldo_rops = {
-	.is_enabled = hi6421_spmi_regulator_is_enabled,
-	.enable = hi6421_spmi_regulator_enable,
-	.disable = hi6421_spmi_regulator_disable,
-	.list_voltage = regulator_list_voltage_table,
-	.map_voltage = regulator_map_voltage_iterate,
-	.get_voltage_sel = hi6421_spmi_regulator_get_voltage_sel,
-	.set_voltage_sel = hi6421_spmi_regulator_set_voltage_sel,
-	.get_mode = hi6421_spmi_regulator_get_mode,
-	.set_mode = hi6421_spmi_regulator_set_mode,
-	.get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode,
-};
-
-static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
-					   struct device_node *np,
-					   struct hi6421_spmi_pmic *pmic)
-{
-	struct regulation_constraints *constraint;
-	struct regulator_init_data *initdata;
-	struct regulator_config config = { };
-	struct hi6421v600_regulator *sreg;
-	struct device *dev = &pdev->dev;
-	struct regulator_desc *rdesc;
-	struct regulator_dev *rdev;
-	const char *supplyname;
-	int ret;
-
-	initdata = of_get_regulator_init_data(dev, np, NULL);
-	if (!initdata) {
-		dev_err(dev, "failed to get regulator data\n");
-		return -EINVAL;
-	}
-
-	sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
-	if (!sreg)
-		return -ENOMEM;
-
-	sreg->pmic = pmic;
-	rdesc = &sreg->rdesc;
-
-	rdesc->name = initdata->constraints.name;
-	rdesc->ops = &hi6421_spmi_ldo_rops;
-	rdesc->type = REGULATOR_VOLTAGE;
-	rdesc->min_uV = initdata->constraints.min_uV;
-
-	supplyname = of_get_property(np, "supply_name", NULL);
-	if (supplyname)
-		initdata->supply_regulator = supplyname;
-
-	/* parse device tree data for regulator specific */
-	ret = hi6421_spmi_dt_parse(pdev, sreg, rdesc);
-	if (ret)
-		return ret;
-
-	/* hisi regulator supports two modes */
-	constraint = &initdata->constraints;
-
-	constraint->valid_modes_mask = REGULATOR_MODE_NORMAL;
-	if (sreg->eco_mode_mask) {
-		constraint->valid_modes_mask |= REGULATOR_MODE_IDLE;
-		constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE;
-	}
-
-	config.dev = &pdev->dev;
-	config.init_data = initdata;
-	config.driver_data = sreg;
-	config.of_node = pdev->dev.of_node;
-
-	/* register regulator */
-	rdev = regulator_register(rdesc, &config);
-	if (IS_ERR(rdev)) {
-		dev_err(dev, "failed to register %s\n",
-			rdesc->name);
-		return PTR_ERR(rdev);
-	}
-
-	rdev_dbg(rdev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
-		 constraint->valid_modes_mask, constraint->valid_ops_mask);
-
-	dev_set_drvdata(dev, rdev);
-
-	return 0;
-}
-
-static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
-{
-	struct device *pmic_dev = pdev->dev.parent;
-	struct device_node *np = pmic_dev->of_node;
-	struct device_node *regulators, *child;
-	struct platform_device *new_pdev;
-	struct hi6421_spmi_pmic *pmic;
-	int ret;
-
-	/*
-	 * This driver is meant to be called by hi6421-spmi-core,
-	 * which should first set drvdata. If this doesn't happen, hit
-	 * a warn on and return.
-	 */
-	pmic = dev_get_drvdata(pmic_dev);
-	if (WARN_ON(!pmic))
-		return -ENODEV;
-
-	regulators = of_get_child_by_name(np, "regulators");
-	if (!regulators) {
-		dev_err(&pdev->dev, "regulator node not found\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * Parse all LDO regulator nodes
-	 */
-	for_each_child_of_node(regulators, child) {
-		dev_dbg(&pdev->dev, "adding child %pOF\n", child);
-
-		new_pdev = platform_device_alloc(child->name, -1);
-		new_pdev->dev.parent = pmic_dev;
-		new_pdev->dev.of_node = of_node_get(child);
-
-		ret = platform_device_add(new_pdev);
-		if (ret < 0) {
-			platform_device_put(new_pdev);
-			continue;
-		}
-
-		ret = hi6421_spmi_regulator_probe_ldo(new_pdev, child, pmic);
-		if (ret < 0)
-			platform_device_put(new_pdev);
-	}
-
-	of_node_put(regulators);
-
-	return 0;
-}
-
-static int hi6421_spmi_regulator_remove(struct platform_device *pdev)
-{
-	struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev);
-	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-
-	regulator_unregister(rdev);
-
-	if (rdev->desc->volt_table)
-		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
-
-	kfree(sreg);
-
-	return 0;
-}
-
-static const struct platform_device_id hi6421v600_regulator_table[] = {
-	{ .name = "hi6421v600-regulator" },
-	{},
-};
-MODULE_DEVICE_TABLE(platform, hi6421v600_regulator_table);
-
-static struct platform_driver hi6421v600_regulator_driver = {
-	.id_table = hi6421v600_regulator_table,
-	.driver = {
-		.name	= "hi6421v600-regulator",
-	},
-	.probe	= hi6421_spmi_regulator_probe,
-	.remove	= hi6421_spmi_regulator_remove,
-};
-module_platform_driver(hi6421v600_regulator_driver);
-
-MODULE_DESCRIPTION("Hi6421v600 regulator driver");
-MODULE_LICENSE("GPL v2");
-
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/8] arm64: dts: hisilicon: hi3670.dtsi: add I2C settings
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2020-11-16 12:59 ` [PATCH 4/8] regulator: hi6421v600-regulator: move it " Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 6/8] arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Wei Xu, devicetree, linux-arm-kernel,
	linux-kernel

The I2C buses are not declared at the device tree. As this will
be needed by further patches, add them, keeping all in
disabled state. Per-board settings can override it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 arch/arm64/boot/dts/hisilicon/hi3670.dtsi | 71 +++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
index 2dcffa3ed218..40a422ddc8ec 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
@@ -709,5 +709,76 @@ dwmmc2: dwmmc2@fc183000 {
 			card-detect-delay = <200>;
 			status = "disabled";
 		};
+
+		/* I2C */
+		i2c0: i2c@ffd71000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0xffd71000 0x0 0x1000>;
+			interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clock-frequency = <400000>;
+			clocks = <&iomcu HI3670_CLK_GATE_I2C0>;
+			resets = <&iomcu_rst 0x20 3>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>;
+			status = "disabled";
+		};
+
+		i2c1: i2c@ffd72000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0xffd72000 0x0 0x1000>;
+			interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clock-frequency = <400000>;
+			clocks = <&iomcu HI3670_CLK_GATE_I2C1>;
+			resets = <&iomcu_rst 0x20 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pmx_func &i2c1_cfg_func>;
+			status = "disabled";
+		};
+
+		i2c2: i2c@ffd73000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0xffd73000 0x0 0x1000>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clock-frequency = <400000>;
+			clocks = <&iomcu HI3670_CLK_GATE_I2C2>;
+			resets = <&iomcu_rst 0x20 5>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c2_pmx_func &i2c2_cfg_func>;
+			status = "disabled";
+		};
+
+		i2c3: i2c@fdf0c000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0xfdf0c000 0x0 0x1000>;
+			interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clock-frequency = <400000>;
+			clocks = <&crg_ctrl HI3670_CLK_GATE_I2C3>;
+			resets = <&crg_rst 0x78 7>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c3_pmx_func &i2c3_cfg_func>;
+			status = "disabled";
+		};
+
+		i2c4: i2c@fdf0d000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0xfdf0d000 0x0 0x1000>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			clock-frequency = <400000>;
+			clocks = <&crg_ctrl HI3670_CLK_GATE_I2C4>;
+			resets = <&crg_rst 0x78 27>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c4_pmx_func &i2c4_cfg_func>;
+			status = "disabled";
+		};
 	};
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 6/8] arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2020-11-16 12:59 ` [PATCH 5/8] arm64: dts: hisilicon: hi3670.dtsi: add I2C settings Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 7/8] dts: hisilicon: add support for USB3 on Hikey 970 Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 8/8] dts: hisilicon: add support for the PMIC found " Mauro Carvalho Chehab
  7 siblings, 0 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Wei Xu, devicetree, linux-arm-kernel,
	linux-kernel

There are several pinctrl settings that are missing at this
DT file.

Also, the entries are out of order.

Add the missing bits, as they'll be required by the DRM driver - and
probably by other drivers not upstreamed yet.

Reorder the entres, adding the missing bits.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../boot/dts/hisilicon/hikey970-pinctrl.dtsi  | 548 +++++++++++++++++-
 1 file changed, 537 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pinctrl.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pinctrl.dtsi
index d456b0aa6f58..75723a1ad5ab 100644
--- a/arch/arm64/boot/dts/hisilicon/hikey970-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hikey970-pinctrl.dtsi
@@ -61,6 +61,153 @@ uart6_pmx_func: uart6_pmx_func {
 					0x060 MUX_M1 /* UART6_TXD */
 				>;
 			};
+
+			i2c3_pmx_func: i2c3_pmx_func {
+				pinctrl-single,pins = <
+					0x010 MUX_M1 /* I2C3_SCL */
+					0x014 MUX_M1 /* I2C3_SDA */
+				>;
+			};
+
+			i2c4_pmx_func: i2c4_pmx_func {
+				pinctrl-single,pins = <
+					0x03c MUX_M1 /* I2C4_SCL */
+					0x040 MUX_M1 /* I2C4_SDA */
+				>;
+			};
+
+			cam0_rst_pmx_func: cam0_rst_pmx_func {
+				pinctrl-single,pins = <
+					0x714 MUX_M0 /* CAM0_RST */
+				>;
+			};
+
+			cam1_rst_pmx_func: cam1_rst_pmx_func {
+				pinctrl-single,pins = <
+					0x048 MUX_M0 /* CAM1_RST */
+				>;
+			};
+
+			cam0_pwd_n_pmx_func: cam0_pwd_n_pmx_func {
+				pinctrl-single,pins = <
+					0x098 MUX_M0 /* CAM0_PWD_N */
+				>;
+			};
+
+			cam1_pwd_n_pmx_func: cam1_pwd_n_pmx_func {
+				pinctrl-single,pins = <
+					0x044 MUX_M0 /* CAM1_PWD_N */
+				>;
+			};
+
+			isp0_pmx_func: isp0_pmx_func {
+				pinctrl-single,pins = <
+					0x018 MUX_M1 /* ISP_CLK0 */
+					0x024 MUX_M1 /* ISP_SCL0 */
+					0x028 MUX_M1 /* ISP_SDA0 */
+				>;
+			};
+
+			isp1_pmx_func: isp1_pmx_func {
+				pinctrl-single,pins = <
+					0x01c MUX_M1 /* ISP_CLK1 */
+					0x02c MUX_M1 /* ISP_SCL1 */
+					0x030 MUX_M1 /* ISP_SDA1 */
+				>;
+			};
+		};
+
+		pmx1: pinmux@fff11000 {
+			compatible = "pinctrl-single";
+			reg = <0x0 0xfff11000 0x0 0x73c>;
+			#gpio-range-cells = <0x3>;
+			#pinctrl-cells = <1>;
+			pinctrl-single,register-width = <0x20>;
+			pinctrl-single,function-mask = <0x7>;
+			/* pin base, nr pins & gpio function */
+			pinctrl-single,gpio-range = <&range 0 46 0>;
+
+			pwr_key_pmx_func: pwr_key_pmx_func {
+				pinctrl-single,pins = <
+					0x064 MUX_M0 /* GPIO_203 */
+				>;
+			};
+
+			pd_pmx_func: pd_pmx_func{
+				pinctrl-single,pins = <
+					0x080 MUX_M0 /* GPIO_221 */
+				>;
+			};
+
+			i2s2_pmx_func: i2s2_pmx_func {
+			    pinctrl-single,pins = <
+					0x050 MUX_M1 /* I2S2_DI */
+					0x054 MUX_M1 /* I2S2_DO */
+					0x058 MUX_M1 /* I2S2_XCLK */
+					0x05c MUX_M1 /* I2S2_XFS */
+			    >;
+			};
+
+			spi0_pmx_func: spi0_pmx_func {
+				pinctrl-single,pins = <
+					0x094 MUX_M1 /* SPI0_CLK */
+					0x098 MUX_M1 /* SPI0_DI */
+					0x09c MUX_M1 /* SPI0_DO */
+					0x0a0 MUX_M1 /* SPI0_CS0_N */
+				>;
+			};
+
+			spi2_pmx_func: spi2_pmx_func {
+				pinctrl-single,pins = <
+					0x710 MUX_M1 /* SPI2_CLK */
+					0x714 MUX_M1 /* SPI2_DI */
+					0x718 MUX_M1 /* SPI2_DO */
+					0x71c MUX_M1 /* SPI2_CS0_N */
+				>;
+			};
+
+			spi3_pmx_func: spi3_pmx_func {
+				pinctrl-single,pins = <
+					0x72c MUX_M1 /* SPI3_CLK */
+					0x730 MUX_M1 /* SPI3_DI */
+					0x734 MUX_M1 /* SPI3_DO */
+					0x738 MUX_M1 /* SPI3_CS0_N */
+				>;
+			};
+
+			i2c0_pmx_func: i2c0_pmx_func {
+				pinctrl-single,pins = <
+					0x020 MUX_M1 /* I2C0_SCL */
+					0x024 MUX_M1 /* I2C0_SDA */
+				>;
+			};
+
+			i2c1_pmx_func: i2c1_pmx_func {
+				pinctrl-single,pins = <
+					0x028 MUX_M1 /* I2C1_SCL */
+					0x02c MUX_M1 /* I2C1_SDA */
+				>;
+			};
+			i2c2_pmx_func: i2c2_pmx_func {
+				pinctrl-single,pins = <
+					0x030 MUX_M1 /* I2C2_SCL */
+					0x034 MUX_M1 /* I2C2_SDA */
+				>;
+			};
+
+			pcie_clkreq_pmx_func: pcie_clkreq_pmx_func {
+				pinctrl-single,pins = <
+					0x084 MUX_M1 /* PCIE0_CLKREQ_N */
+				>;
+			};
+
+			gpio185_pmx_func: gpio185_pmx_func {
+				pinctrl-single,pins = <0x01C    0x1>;
+			};
+
+			gpio185_pmx_idle: gpio185_pmx_idle {
+				pinctrl-single,pins = <0x01C    0x0>;
+			};
 		};
 
 		pmx2: pinmux@e896c800 {
@@ -184,6 +331,108 @@ PULL_UP
 					DRIVE7_02MA DRIVE6_MASK
 				>;
 			};
+
+			i2c3_cfg_func: i2c3_cfg_func {
+				pinctrl-single,pins = <
+					0x014 0x0 /* I2C3_SCL */
+					0x018 0x0 /* I2C3_SDA */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_04MA DRIVE6_MASK
+				>;
+			};
+
+			i2c4_cfg_func: i2c4_cfg_func {
+				pinctrl-single,pins = <
+					0x040 0x0 /* I2C4_SCL */
+					0x044 0x0 /* I2C4_SDA */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_04MA DRIVE6_MASK
+				>;
+			};
+
+			cam0_rst_cfg_func: cam0_rst_cfg_func {
+				pinctrl-single,pins = <
+					0x714 0x0 /* CAM0_RST */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
+
+			cam1_rst_cfg_func: cam1_rst_cfg_func {
+				pinctrl-single,pins = <
+					0x04C 0x0 /* CAM1_RST */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
+
+			cam0_pwd_n_cfg_func: cam0_pwd_n_cfg_func {
+				pinctrl-single,pins = <
+					0x09C 0x0 /* CAM0_PWD_N */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
+
+			cam1_pwd_n_cfg_func: cam1_pwd_n_cfg_func {
+				pinctrl-single,pins = <
+					0x048 0x0 /* CAM1_PWD_N */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
+
+			isp0_cfg_func: isp0_cfg_func {
+				pinctrl-single,pins = <
+					0x01C 0x0 /* ISP_CLK0 */
+					0x028 0x0 /* ISP_SCL0 */
+					0x02C 0x0 /* ISP_SDA0 */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
+
+			isp1_cfg_func: isp1_cfg_func {
+				pinctrl-single,pins = <
+					0x020 0x0 /* ISP_CLK1 */
+					0x030 0x0 /* ISP_SCL1 */
+					0x034 0x0 /* ISP_SDA1 */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_DIS  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_04MA DRIVE6_MASK>;
+			};
 		};
 
 		pmx5: pinmux@fc182000 {
@@ -338,22 +587,299 @@ DRIVE6_MASK
 			};
 		};
 
-		pmx1: pinmux@fff11000 {
-			compatible = "pinctrl-single";
-			reg = <0x0 0xfff11000 0x0 0x73c>;
-			#gpio-range-cells = <0x3>;
-			#pinctrl-cells = <1>;
-			pinctrl-single,register-width = <0x20>;
-			pinctrl-single,function-mask = <0x7>;
-			/* pin base, nr pins & gpio function */
-			pinctrl-single,gpio-range = <&range 0 46 0>;
-		};
-
 		pmx16: pinmux@fff11800 {
 			compatible = "pinconf-single";
 			reg = <0x0 0xfff11800 0x0 0x73c>;
 			#pinctrl-cells = <1>;
 			pinctrl-single,register-width = <0x20>;
+
+			pwr_key_cfg_func: pwr_key_cfg_func {
+				pinctrl-single,pins = <
+					0x090 0x0 /* GPIO_203 */
+				>;
+				pinctrl-single,bias-pulldown  = <PULL_DIS PULL_DOWN PULL_DIS  PULL_DOWN>;
+				pinctrl-single,bias-pullup    = <PULL_UP  PULL_UP   PULL_DIS  PULL_UP>;
+				pinctrl-single,drive-strength = <DRIVE7_02MA DRIVE6_MASK>;
+			};
+
+			usb_cfg_func: usb_cfg_func {
+				pinctrl-single,pins = <
+					0x0AC 0x0 /* GPIO_221 */
+				>;
+				pinctrl-single,bias-pulldown  = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup    = <
+					PULL_UP
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_02MA DRIVE6_MASK
+				>;
+			};
+
+			spi0_cfg_func: spi0_cfg_func {
+				pinctrl-single,pins = <
+					0x0c8 0x0 /* SPI0_DI */
+					0x0cc 0x0 /* SPI0_DO */
+					0x0d0 0x0 /* SPI0_CS0_N */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_06MA DRIVE6_MASK
+				>;
+			};
+
+			spi2_cfg_func: spi2_cfg_func {
+				pinctrl-single,pins = <
+					0x714 0x0 /* SPI2_DI */
+					0x718 0x0 /* SPI2_DO */
+					0x71c 0x0 /* SPI2_CS0_N */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_06MA DRIVE6_MASK
+				>;
+			};
+
+			spi3_cfg_func: spi3_cfg_func {
+				pinctrl-single,pins = <
+					0x730 0x0 /* SPI3_DI */
+					0x734 0x0 /* SPI3_DO */
+					0x738 0x0 /* SPI3_CS0_N */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_06MA DRIVE6_MASK
+				>;
+			};
+
+			spi0_clk_cfg_func: spi0_clk_cfg_func {
+				pinctrl-single,pins = <
+					0x0c4 0x0 /* SPI0_CLK */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_10MA DRIVE6_MASK
+				>;
+			};
+
+			spi2_clk_cfg_func: spi2_clk_cfg_func {
+				pinctrl-single,pins = <
+					0x710 0x0 /* SPI2_CLK */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_10MA DRIVE6_MASK
+				>;
+			};
+
+			spi3_clk_cfg_func: spi3_clk_cfg_func {
+				pinctrl-single,pins = <
+					0x72c 0x0 /* SPI3_CLK */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_10MA DRIVE6_MASK
+				>;
+			};
+
+			i2c0_cfg_func: i2c0_cfg_func {
+				pinctrl-single,pins = <
+					0x04c 0x0 /* I2C0_SCL */
+					0x050 0x0 /* I2C0_SDA */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_04MA DRIVE6_MASK
+				>;
+			};
+
+			i2c1_cfg_func: i2c1_cfg_func {
+				pinctrl-single,pins = <
+					0x054 0x0 /* I2C1_SCL */
+					0x058 0x0 /* I2C1_SDA */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_04MA DRIVE6_MASK
+				>;
+			};
+
+			i2c2_cfg_func: i2c2_cfg_func {
+				pinctrl-single,pins = <
+					0x05c 0x0 /* I2C2_SCL */
+					0x060 0x0 /* I2C2_SDA */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_04MA DRIVE6_MASK
+				>;
+			};
+
+			pcie_clkreq_cfg_func: pcie_clkreq_cfg_func {
+				pinctrl-single,pins = <
+					0x0b0 0x0
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_DIS
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_06MA DRIVE6_MASK
+				>;
+			};
+			i2s2_cfg_func: i2s2_cfg_func {
+				pinctrl-single,pins = <
+					0x07c 0x0 /* I2S2_DI */
+					0x080 0x0 /* I2S2_DO */
+					0x084 0x0 /* I2S2_XCLK */
+					0x088 0x0 /* I2S2_XFS */
+				>;
+				pinctrl-single,bias-pulldown = <
+					PULL_DIS
+					PULL_DOWN
+					PULL_DIS
+					PULL_DOWN
+				>;
+				pinctrl-single,bias-pullup = <
+					PULL_UP
+					PULL_UP
+					PULL_DIS
+					PULL_UP
+				>;
+				pinctrl-single,drive-strength = <
+					DRIVE7_02MA DRIVE6_MASK
+				>;
+			};
+
+			gpio185_cfg_func: gpio185_cfg_func {
+				pinctrl-single,pins = <0x048  0>;
+				pinctrl-single,bias-pulldown = <0 2 0 2>;
+				pinctrl-single,bias-pullup = <0 1 0 1>;
+				pinctrl-single,drive-strength = <0x00 0x70>;
+				pinctrl-single,slew-rate = <0x0 0x80>;
+			};
+
+			gpio185_cfg_idle: gpio185_cfg_idle {
+				pinctrl-single,pins = <0x048  0>;
+				pinctrl-single,bias-pulldown = <2 2 0 2>;
+				pinctrl-single,bias-pullup = <0 1 0 1>;
+				pinctrl-single,drive-strength = <0x00 0x70>;
+				pinctrl-single,slew-rate = <0x0 0x80>;
+			};
 		};
 	};
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 7/8] dts: hisilicon: add support for USB3 on Hikey 970
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
                   ` (5 preceding siblings ...)
  2020-11-16 12:59 ` [PATCH 6/8] arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  2020-11-16 12:59 ` [PATCH 8/8] dts: hisilicon: add support for the PMIC found " Mauro Carvalho Chehab
  7 siblings, 0 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Wei Xu, devicetree, linux-arm-kernel,
	linux-kernel

Add the USB3 bindings for Kirin 970 phy and Hikey 970 board.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../boot/dts/hisilicon/hi3670-hikey970.dts    | 102 ++++++++++++++++++
 arch/arm64/boot/dts/hisilicon/hi3670.dtsi     |  64 +++++++++++
 2 files changed, 166 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
index 7f9f9886c349..fe6600dbad61 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
@@ -69,6 +69,29 @@ wlan_en: wlan-en-1-8v {
 		startup-delay-us = <70000>;
 		enable-active-high;
 	};
+	hikey_usbhub: hikey_usbhub {
+		compatible = "hisilicon,kirin970_hikey_usbhub";
+
+		typec-vbus-gpios = <&gpio26 1 0>;
+		otg-switch-gpios = <&gpio4 2 0>;
+		hub_reset_en_gpio = <&gpio0 3 0>;
+		hub-vdd-supply = <&ldo17>;
+		usb-role-switch;
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			hikey_usb_ep0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&dwc3_role_switch>;
+			};
+			hikey_usb_ep1: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&rt1711h_ep>;
+			};
+		};
+	};
 };
 
 /*
@@ -446,3 +469,82 @@ &uart6 {
 	label = "LS-UART1";
 	status = "okay";
 };
+
+&i2c1 {
+	status = "okay";
+
+	rt1711h: rt1711h@4e {
+		compatible = "richtek,rt1711h";
+		reg = <0x4e>;
+		status = "okay";
+		interrupt-parent = <&gpio27>;
+		interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb_cfg_func>;
+
+		usb_con: connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			power-role = "dual";
+			try-power-role = "sink";
+			source-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)>;
+			sink-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)
+				PDO_VAR(5000, 5000, 1000)>;
+			op-sink-microwatt = <10000000>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				port@1 {
+					reg = <1>;
+					usb_con_ss: endpoint {
+						remote-endpoint = <&dwc3_ss>;
+					};
+				};
+			};
+		};
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rt1711h_ep: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&hikey_usb_ep1>;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	/* USB HUB is on this bus at address 0x44 */
+	status = "okay";
+};
+
+&dwc3 { /* USB */
+	dr_mode = "otg";
+	maximum-speed = "super-speed";
+	phy_type = "utmi";
+	snps,dis-del-phy-power-chg-quirk;
+	snps,dis_u2_susphy_quirk;
+	snps,dis_u3_susphy_quirk;
+	snps,tx_de_emphasis_quirk;
+	snps,tx_de_emphasis = <1>;
+	snps,dis-split-quirk;
+	snps,gctl-reset-quirk;
+	usb-role-switch;
+	role-switch-default-mode = "host";
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		dwc3_role_switch: endpoint@0 {
+			reg = <0>;
+			remote-endpoint = <&hikey_usb_ep0>;
+		};
+
+		dwc3_ss: endpoint@1 {
+			reg = <1>;
+			remote-endpoint = <&usb_con_ss>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
index 40a422ddc8ec..d44af856f90d 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
@@ -8,6 +8,7 @@
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/clock/hi3670-clock.h>
+#include <dt-bindings/usb/pd.h>
 
 / {
 	compatible = "hisilicon,hi3670";
@@ -194,6 +195,12 @@ media2_crg: media2_crgctrl@e8900000 {
 			#clock-cells = <1>;
 		};
 
+		iomcu_rst: reset {
+			compatible = "hisilicon,hi3660-reset";
+			hisi,rst-syscon = <&iomcu>;
+			#reset-cells = <2>;
+		};
+
 		uart0: serial@fdf02000 {
 			compatible = "arm,pl011", "arm,primecell";
 			reg = <0x0 0xfdf02000 0x0 0x1000>;
@@ -780,5 +787,62 @@ i2c4: i2c@fdf0d000 {
 			pinctrl-0 = <&i2c4_pmx_func &i2c4_cfg_func>;
 			status = "disabled";
 		};
+
+		usb3_otg_bc: usb3_otg_bc@ff200000 {
+			compatible = "syscon", "simple-mfd";
+			reg = <0x0 0xff200000 0x0 0x1000>;
+
+			usb_phy: usbphy {
+				compatible = "hisilicon,hi3670-usb-phy";
+				#phy-cells = <0>;
+				hisilicon,pericrg-syscon = <&crg_ctrl>;
+				hisilicon,pctrl-syscon = <&pctrl>;
+				hisilicon,sctrl-syscon = <&sctrl>;
+				hisilicon,eye-diagram-param = <0xFDFEE4>;
+				hisilicon,tx-vboost-lvl = <0x5>;
+
+				phy-supply = <&ldo17>;
+			};
+		};
+
+		usb31_misc_rst: usb31_misc_rst_controller {
+			compatible = "hisilicon,hi3660-reset";
+			#reset-cells = <2>;
+			hisi,rst-syscon = <&usb3_otg_bc>;
+		};
+
+		usb3: hisi_dwc3 {
+			compatible = "hisilicon,hi3670-dwc3";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+
+			clocks = <&crg_ctrl HI3670_CLK_GATE_ABB_USB>,
+				  <&crg_ctrl HI3670_HCLK_GATE_USB3OTG>,
+				  <&crg_ctrl HI3670_CLK_GATE_USB3OTG_REF>,
+				  <&crg_ctrl HI3670_ACLK_GATE_USB3DVFS>;
+			clock-names = "clk_gate_abb_usb",
+				      "hclk_gate_usb3otg",
+				      "clk_gate_usb3otg_ref",
+				      "aclk_gate_usb3dvfs";
+
+			assigned-clocks = <&crg_ctrl HI3670_ACLK_GATE_USB3DVFS>;
+			assigned-clock-rates = <238000000>;
+			resets = <&crg_rst 0x90 6>,
+				 <&crg_rst 0x90 7>,
+				 <&usb31_misc_rst 0xA0 8>,
+				 <&usb31_misc_rst 0xA0 9>;
+
+			dwc3: dwc3@ff100000 {
+				compatible = "snps,dwc3";
+				reg = <0x0 0xff100000 0x0 0x100000>;
+
+				interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>,
+					    <0 161 IRQ_TYPE_LEVEL_HIGH>;
+
+				phys = <&usb_phy>;
+				phy-names = "usb3-phy";
+			};
+		};
 	};
 };
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 8/8] dts: hisilicon: add support for the PMIC found on Hikey 970
  2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
                   ` (6 preceding siblings ...)
  2020-11-16 12:59 ` [PATCH 7/8] dts: hisilicon: add support for USB3 on Hikey 970 Mauro Carvalho Chehab
@ 2020-11-16 12:59 ` Mauro Carvalho Chehab
  7 siblings, 0 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-16 12:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, John Stultz,
	Manivannan Sadhasivam, Wei Xu, devicetree, linux-arm-kernel,
	linux-kernel

Add a device tree for the HiSilicon 6421v600 SPMI PMIC, used
on HiKey970 board.

As we now have support for it, change the fixed regulators
used by the SD I/O to use the proper LDO supplies.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../boot/dts/hisilicon/hi3670-hikey970.dts    |  22 +-
 .../boot/dts/hisilicon/hikey970-pmic.dtsi     | 197 ++++++++++++++++++
 2 files changed, 200 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi

diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
index fe6600dbad61..1f221cb97690 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
@@ -12,6 +12,7 @@
 
 #include "hi3670.dtsi"
 #include "hikey970-pinctrl.dtsi"
+#include "hikey970-pmic.dtsi"
 
 / {
 	model = "HiKey970";
@@ -39,23 +40,6 @@ memory@0 {
 		reg = <0x0 0x0 0x0 0x0>;
 	};
 
-	sd_1v8: regulator-1v8 {
-		compatible = "regulator-fixed";
-		regulator-name = "fixed-1.8V";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <1800000>;
-		regulator-always-on;
-	};
-
-	sd_3v3: regulator-3v3 {
-		compatible = "regulator-fixed";
-		regulator-name = "fixed-3.3V";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-boot-on;
-		regulator-always-on;
-	};
-
 	wlan_en: wlan-en-1-8v {
 		compatible = "regulator-fixed";
 		regulator-name = "wlan-en-regulator";
@@ -425,8 +409,8 @@ &dwmmc1 {
 	pinctrl-0 = <&sd_pmx_func
 		     &sd_clk_cfg_func
 		     &sd_cfg_func>;
-	vmmc-supply = <&sd_3v3>;
-	vqmmc-supply = <&sd_1v8>;
+	vmmc-supply = <&ldo16>;
+	vqmmc-supply = <&ldo9>;
 	status = "okay";
 };
 
diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
new file mode 100644
index 000000000000..7d79017ccfa5
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dts file for Hi6421v600 SPMI PMIC used at the HiKey970 Development Board
+ *
+ * Copyright (C) 2020, Huawei Tech. Co., Ltd.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+	spmi: spmi@fff24000 {
+		compatible = "hisilicon,kirin970-spmi-controller";
+		#address-cells = <2>;
+		#size-cells = <0>;
+		status = "okay";
+		reg = <0x0 0xfff24000 0x0 0x1000>;
+		spmi-channel = <2>;
+
+		pmic: pmic@0 {
+			compatible = "hisilicon,hi6421-spmi";
+			reg = <0 SPMI_USID>;
+
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			gpios = <&gpio28 0 0>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				ldo3: ldo3@16 {
+					reg = <0x16>;
+					vsel-reg = <0x51>;
+
+					regulator-name = "ldo3";
+					regulator-min-microvolt = <1500000>;
+					regulator-max-microvolt = <2000000>;
+					regulator-boot-on;
+
+					enable-mask = <0x01>;
+
+					voltage-table = <1500000>, <1550000>,
+							<1600000>, <1650000>,
+							<1700000>, <1725000>,
+							<1750000>, <1775000>,
+							<1800000>, <1825000>,
+							<1850000>, <1875000>,
+							<1900000>, <1925000>,
+							<1950000>, <2000000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+
+				ldo4: ldo4@17 { /* 40 PIN */
+					reg = <0x17>;
+					vsel-reg = <0x52>;
+
+					regulator-name = "ldo4";
+					regulator-min-microvolt = <1725000>;
+					regulator-max-microvolt = <1900000>;
+					regulator-boot-on;
+
+					enable-mask = <0x01>;
+					idle-mode-mask = <0x10>;
+					eco-microamp = <10000>;
+
+					hi6421-vsel = <0x52 0x07>;
+					voltage-table = <1725000>, <1750000>,
+							<1775000>, <1800000>,
+							<1825000>, <1850000>,
+							<1875000>, <1900000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+
+				ldo9: ldo9@1C { /* SDCARD I/O */
+					reg = <0x1C>;
+					vsel-reg = <0x57>;
+
+					regulator-name = "ldo9";
+					regulator-min-microvolt = <1750000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-boot-on;
+
+					enable-mask = <0x01>;
+					idle-mode-mask = <0x10>;
+					eco-microamp = <10000>;
+
+					voltage-table = <1750000>, <1800000>,
+							<1825000>, <2800000>,
+							<2850000>, <2950000>,
+							<3000000>, <3300000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <360>;
+				};
+
+				ldo15: ldo15@21 { /* UFS */
+					reg = <0x21>;
+					vsel-reg = <0x5c>;
+
+					regulator-name = "ldo15";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <3000000>;
+					regulator-always-on;
+
+					enable-mask = <0x01>;
+					idle-mode-mask = <0x10>;
+					eco-microamp = <10000>;
+
+					voltage-table = <1800000>, <1850000>,
+							<2400000>, <2600000>,
+							<2700000>, <2850000>,
+							<2950000>, <3000000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+
+				ldo16: ldo16@22 { /* SD */
+					reg = <0x22>;
+					vsel-reg = <0x5d>;
+
+					regulator-name = "ldo16";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <3000000>;
+					regulator-boot-on;
+
+					enable-mask = <0x01>;
+					idle-mode-mask = <0x10>;
+					eco-microamp = <10000>;
+
+					voltage-table = <1800000>, <1850000>,
+							<2400000>, <2600000>,
+							<2700000>, <2850000>,
+							<2950000>, <3000000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <360>;
+				};
+
+				ldo17: ldo17@23 {
+					reg = <0x23>;
+					vsel-reg = <0x5e>;
+
+					regulator-name = "ldo17";
+					regulator-min-microvolt = <2500000>;
+					regulator-max-microvolt = <3300000>;
+
+					enable-mask = <0x01>;
+					idle-mode-mask = <0x10>;
+					eco-microamp = <10000>;
+
+					voltage-table = <2500000>, <2600000>,
+							<2700000>, <2800000>,
+							<3000000>, <3100000>,
+							<3200000>, <3300000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+
+				ldo33: ldo33@32 { /* PEX8606 */
+					reg = <0x32>;
+					vsel-reg = <0x6d>;
+					regulator-name = "ldo33";
+					regulator-min-microvolt = <2500000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-boot-on;
+
+					enable-mask = <0x01>;
+
+					voltage-table = <2500000>, <2600000>,
+							<2700000>, <2800000>,
+							<3000000>, <3100000>,
+							<3200000>, <3300000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+
+				ldo34: ldo34@33 { /* GPS AUX IN VDD */
+					reg = <0x33>;
+					vsel-reg = <0x6e>;
+
+					regulator-name = "ldo34";
+					regulator-min-microvolt = <2600000>;
+					regulator-max-microvolt = <3300000>;
+
+					enable-mask = <0x01>;
+
+					voltage-table = <2600000>, <2700000>,
+							<2800000>, <2900000>,
+							<3000000>, <3100000>,
+							<3200000>, <3300000>;
+					off-on-delay-us = <20000>;
+					startup-delay-us = <120>;
+				};
+			};
+		};
+	};
+};
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
@ 2020-11-16 15:31   ` Rob Herring
  2020-11-17  6:55     ` Mauro Carvalho Chehab
  2020-11-16 15:31   ` Rob Herring
  2020-11-30 10:30   ` Vinod Koul
  2 siblings, 1 reply; 21+ messages in thread
From: Rob Herring @ 2020-11-16 15:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Vinod Koul, linuxarm, mauro.chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Krzysztof Kozlowski, Yu Chen, devel,
	devicetree, linux-kernel

On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote:
> The phy USB3 driver for Hisilicon 970 (hi3670) is ready
> for mainstream. Mode it from staging into the main driver's

s/Mode/Move/

> phy/ directory.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
>  MAINTAINERS                                   |   9 +-
>  drivers/phy/hisilicon/Kconfig                 |  10 +
>  drivers/phy/hisilicon/Makefile                |   1 +
>  drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
>  drivers/staging/hikey9xx/Kconfig              |  11 -
>  drivers/staging/hikey9xx/Makefile             |   2 -
>  drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
>  drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --

I assume this is only a move? Use '-M' option.

>  9 files changed, 762 insertions(+), 757 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
>  create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c
>  delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c
>  delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
> 
> diff --git a/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
> new file mode 100644
> index 000000000000..125a5d6546ae
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
> @@ -0,0 +1,72 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Hisilicon Kirin970 USB PHY
> +
> +maintainers:
> +  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +description: |+
> +  Bindings for USB3 PHY on HiSilicon Kirin 970.
> +
> +properties:
> +  compatible:
> +    const: hisilicon,hi3670-usb-phy
> +
> +  "#phy-cells":
> +    const: 0
> +
> +  hisilicon,pericrg-syscon:
> +    $ref: '/schemas/types.yaml#/definitions/phandle'
> +    description: phandle of syscon used to control iso refclk.
> +
> +  hisilicon,pctrl-syscon:
> +    $ref: '/schemas/types.yaml#/definitions/phandle'
> +    description: phandle of syscon used to control usb tcxo.
> +
> +  hisilicon,sctrl-syscon:
> +    $ref: '/schemas/types.yaml#/definitions/phandle'
> +    description: phandle of syscon used to control phy deep sleep.
> +
> +  hisilicon,eye-diagram-param:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: Eye diagram for phy.
> +
> +  hisilicon,tx-vboost-lvl:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: TX level vboost for phy.
> +
> +required:
> +  - compatible
> +  - hisilicon,pericrg-syscon
> +  - hisilicon,pctrl-syscon
> +  - hisilicon,sctrl-syscon
> +  - hisilicon,eye-diagram-param
> +  - hisilicon,tx-vboost-lvl
> +  - "#phy-cells"
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    bus {
> +      #address-cells = <2>;
> +      #size-cells = <2>;
> +
> +      usb3_otg_bc: usb3_otg_bc@ff200000 {
> +        compatible = "syscon", "simple-mfd";
> +        reg = <0x0 0xff200000 0x0 0x1000>;
> +
> +        usb_phy {
> +          compatible = "hisilicon,hi3670-usb-phy";
> +          #phy-cells = <0>;
> +          hisilicon,pericrg-syscon = <&crg_ctrl>;
> +          hisilicon,pctrl-syscon = <&pctrl>;
> +          hisilicon,sctrl-syscon = <&sctrl>;
> +          hisilicon,eye-diagram-param = <0xfdfee4>;
> +          hisilicon,tx-vboost-lvl = <0x5>;
> +        };
> +      };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e451dcce054f..14266bb79ff8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -18083,7 +18083,7 @@ L:	linux-usb@vger.kernel.org
>  S:	Maintained
>  F:	drivers/usb/roles/intel-xhci-usb-role-switch.c
>  
> -USB IP DRIVER FOR HISILICON KIRIN
> +USB IP DRIVER FOR HISILICON KIRIN 960
>  M:	Yu Chen <chenyu56@huawei.com>
>  M:	Binghui Wang <wangbinghui@hisilicon.com>
>  L:	linux-usb@vger.kernel.org
> @@ -18091,6 +18091,13 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
>  F:	drivers/phy/hisilicon/phy-hi3660-usb3.c
>  
> +USB IP DRIVER FOR HISILICON KIRIN 970
> +M:	Mauro Carvalho Chehab <mchehab@kernel.org>
> +L:	linux-usb@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/phy/hisilicon,kirin970-usb3.yaml
> +F:	drivers/phy/hisilicon/phy-kirin970-usb3.c
> +
>  USB ISP116X DRIVER
>  M:	Olav Kongas <ok@artecdesign.ee>
>  L:	linux-usb@vger.kernel.org
> diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig
> index 1c73053bcc98..4d008cfc279c 100644
> --- a/drivers/phy/hisilicon/Kconfig
> +++ b/drivers/phy/hisilicon/Kconfig
> @@ -23,6 +23,16 @@ config PHY_HI3660_USB
>  
>  	  To compile this driver as a module, choose M here.
>  
> +config PHY_HI3670_USB
> +	tristate "hi3670 USB PHY support"
> +	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
> +	select GENERIC_PHY
> +	select MFD_SYSCON
> +	help
> +	  Enable this to support the HISILICON HI3670 USB PHY.
> +
> +	  To compile this driver as a module, choose M here.
> +
>  config PHY_HISTB_COMBPHY
>  	tristate "HiSilicon STB SoCs COMBPHY support"
>  	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
> diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile
> index 92e874ae9c74..51729868145b 100644
> --- a/drivers/phy/hisilicon/Makefile
> +++ b/drivers/phy/hisilicon/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  obj-$(CONFIG_PHY_HI6220_USB)		+= phy-hi6220-usb.o
>  obj-$(CONFIG_PHY_HI3660_USB)		+= phy-hi3660-usb3.o
> +obj-$(CONFIG_PHY_HI3670_USB)		+= phy-hi3670-usb3.o
>  obj-$(CONFIG_PHY_HISTB_COMBPHY)		+= phy-histb-combphy.o
>  obj-$(CONFIG_PHY_HISI_INNO_USB2)	+= phy-hisi-inno-usb2.o
>  obj-$(CONFIG_PHY_HIX5HD2_SATA)		+= phy-hix5hd2-sata.o
> diff --git a/drivers/phy/hisilicon/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c
> new file mode 100644
> index 000000000000..4fc013911a78
> --- /dev/null
> +++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c
> @@ -0,0 +1,671 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
> + *
> + * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
> + *		http://www.huawei.com
> + *
> + * Authors: Yu Chen <chenyu56@huawei.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#define SCTRL_SCDEEPSLEEPED		(0x0)
> +#define USB_CLK_SELECTED		BIT(20)
> +
> +#define PERI_CRG_PEREN0			(0x00)
> +#define PERI_CRG_PERDIS0		(0x04)
> +#define PERI_CRG_PEREN4			(0x40)
> +#define PERI_CRG_PERDIS4		(0x44)
> +#define PERI_CRG_PERRSTEN4		(0x90)
> +#define PERI_CRG_PERRSTDIS4		(0x94)
> +#define PERI_CRG_ISODIS			(0x148)
> +#define PERI_CRG_PEREN6			(0x410)
> +#define PERI_CRG_PERDIS6		(0x414)
> +
> +#define USB_REFCLK_ISO_EN		BIT(25)
> +
> +#define GT_CLK_USB2PHY_REF		BIT(19)
> +
> +#define PCTRL_PERI_CTRL3		(0x10)
> +#define PCTRL_PERI_CTRL3_MSK_START	(16)
> +#define USB_TCXO_EN			BIT(1)
> +
> +#define PCTRL_PERI_CTRL24		(0x64)
> +#define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
> +
> +#define USB3OTG_CTRL0			(0x00)
> +#define USB3OTG_CTRL3			(0x0C)
> +#define USB3OTG_CTRL4			(0x10)
> +#define USB3OTG_CTRL5			(0x14)
> +#define USB3OTG_CTRL7			(0x1C)
> +#define USB_MISC_CFG50			(0x50)
> +#define USB_MISC_CFG54			(0x54)
> +#define USB_MISC_CFG58			(0x58)
> +#define USB_MISC_CFG5C			(0x5C)
> +#define USB_MISC_CFGA0			(0xA0)
> +#define TCA_CLK_RST			(0x200)
> +#define TCA_INTR_EN			(0x204)
> +#define TCA_INTR_STS			(0x208)
> +#define TCA_GCFG			(0x210)
> +#define TCA_TCPC			(0x214)
> +#define TCA_SYSMODE_CFG			(0x218)
> +#define TCA_VBUS_CTRL			(0x240)
> +
> +#define CTRL0_USB3_VBUSVLD		BIT(7)
> +#define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
> +
> +#define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
> +#define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
> +
> +#define CTRL5_USB2_SIDDQ		BIT(0)
> +
> +#define CTRL7_USB2_REFCLKSEL_MASK	(3 << 3)
> +#define CTRL7_USB2_REFCLKSEL_ABB	(3 << 3)
> +#define CTRL7_USB2_REFCLKSEL_PAD	(2 << 3)
> +
> +#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
> +
> +#define CFG54_USB31PHY_CR_ADDR_MASK	(0xFFFF)
> +#define CFG54_USB31PHY_CR_ADDR_SHIFT	(16)
> +#define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
> +#define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
> +#define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
> +#define CFG54_USB31PHY_CR_ACK		BIT(7)
> +#define CFG54_USB31PHY_CR_WR_EN		BIT(5)
> +#define CFG54_USB31PHY_CR_SEL		BIT(4)
> +#define CFG54_USB31PHY_CR_RD_EN		BIT(3)
> +#define CFG54_USB31PHY_CR_CLK		BIT(2)
> +#define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
> +
> +#define CFG58_USB31PHY_CR_DATA_MASK     (0xFFFF)
> +#define CFG58_USB31PHY_CR_DATA_RD_START (16)
> +
> +#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
> +
> +#define CFGA0_VAUX_RESET		BIT(9)
> +#define CFGA0_USB31C_RESET		BIT(8)
> +#define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
> +#define CFGA0_USB3PHY_RESET		BIT(1)
> +#define CFGA0_USB2PHY_POR		BIT(0)
> +
> +#define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
> +#define INTR_EN_XA_ACK_EVT_EN		BIT(0)
> +
> +#define CLK_RST_TCA_REF_CLK_EN		BIT(1)
> +#define CLK_RST_SUSPEND_CLK_EN		BIT(0)
> +
> +#define GCFG_ROLE_HSTDEV		BIT(4)
> +#define GCFG_OP_MODE			(3 << 0)
> +#define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
> +
> +#define TCPC_VALID			BIT(4)
> +#define TCPC_LOW_POWER_EN		BIT(3)
> +#define TCPC_MUX_CONTROL_MASK		(3 << 0)
> +#define TCPC_MUX_CONTROL_USB31		BIT(0)
> +
> +#define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
> +
> +#define VBUS_CTRL_POWERPRESENT_OVERRD	(3 << 2)
> +#define VBUS_CTRL_VBUSVALID_OVERRD	(3 << 0)
> +
> +#define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xFDFEE4)
> +#define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
> +
> +#define TX_VBOOST_LVL_REG		(0xf)
> +#define TX_VBOOST_LVL_START		(6)
> +#define TX_VBOOST_LVL_ENABLE		BIT(9)
> +
> +struct hi3670_priv {
> +	struct device *dev;
> +	struct regmap *peri_crg;
> +	struct regmap *pctrl;
> +	struct regmap *sctrl;
> +	struct regmap *usb31misc;
> +
> +	u32 eye_diagram_param;
> +	u32 tx_vboost_lvl;
> +
> +	u32 peri_crg_offset;
> +	u32 pctrl_offset;
> +	u32 usb31misc_offset;
> +};
> +
> +static int hi3670_phy_cr_clk(struct regmap *usb31misc)
> +{
> +	int ret;
> +
> +	/* Clock up */
> +	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
> +	if (ret)
> +		return ret;
> +
> +	/* Clock down */
> +	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +				 CFG54_USB31PHY_CR_CLK, 0);
> +
> +	return ret;
> +}
> +
> +static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
> +{
> +	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
> +}
> +
> +static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
> +{
> +	int ret;
> +
> +	if (direction)
> +		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +					 CFG54_USB31PHY_CR_WR_EN,
> +					 CFG54_USB31PHY_CR_WR_EN);
> +	else
> +		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +					 CFG54_USB31PHY_CR_RD_EN,
> +					 CFG54_USB31PHY_CR_RD_EN);
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_clk(usb31misc);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +				 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
> +
> +	return ret;
> +}
> +
> +static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
> +{
> +	u32 reg;
> +	int retry = 100000;
> +	int ret;
> +
> +	while (retry-- > 0) {
> +		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> +		if (ret)
> +			return ret;
> +		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
> +			return 0;
> +
> +		ret = hi3670_phy_cr_clk(usb31misc);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
> +{
> +	u32 reg;
> +	int ret;
> +
> +	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> +	if (ret)
> +		return ret;
> +
> +	reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT);
> +	reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT);
> +	ret = regmap_write(usb31misc, USB_MISC_CFG54, reg);
> +
> +	return ret;
> +}
> +
> +static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
> +{
> +	int reg;
> +	int i;
> +	int ret;
> +
> +	for (i = 0; i < 100; i++) {
> +		ret = hi3670_phy_cr_clk(usb31misc);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = hi3670_phy_cr_set_sel(usb31misc);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_start(usb31misc, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_wait_ack(usb31misc);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
> +	if (ret)
> +		return ret;
> +
> +	*val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) &
> +		CFG58_USB31PHY_CR_DATA_MASK;
> +
> +	return 0;
> +}
> +
> +static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
> +{
> +	int i;
> +	int ret;
> +
> +	for (i = 0; i < 100; i++) {
> +		ret = hi3670_phy_cr_clk(usb31misc);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = hi3670_phy_cr_set_sel(usb31misc);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_write(usb31misc, USB_MISC_CFG58,
> +			   val & CFG58_USB31PHY_CR_DATA_MASK);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_start(usb31misc, 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_wait_ack(usb31misc);
> +
> +	return ret;
> +}
> +
> +static int hi3670_phy_set_params(struct hi3670_priv *priv)
> +{
> +	u32 reg;
> +	int ret;
> +	int retry = 3;
> +
> +	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
> +			   priv->eye_diagram_param);
> +	if (ret) {
> +		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
> +		return ret;
> +	}
> +
> +	while (retry-- > 0) {
> +		ret = hi3670_phy_cr_read(priv->usb31misc,
> +					 TX_VBOOST_LVL_REG, &reg);
> +		if (!ret)
> +			break;
> +
> +		if (ret != -ETIMEDOUT) {
> +			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
> +			return ret;
> +		}
> +	}
> +	if (ret)
> +		return ret;
> +
> +	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
> +	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
> +	if (ret)
> +		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
> +
> +	return ret;
> +}
> +
> +static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv)
> +{
> +	u32 reg;
> +
> +	if (!priv->sctrl) {
> +		dev_err(priv->dev, "priv->sctrl is null!\n");
> +		return 1;
> +	}
> +
> +	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
> +		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
> +		return 1;
> +	}
> +
> +	if ((reg & USB_CLK_SELECTED) == 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int hi3670_config_phy_clock(struct hi3670_priv *priv)
> +{
> +	u32 val, mask;
> +	int ret;
> +
> +	if (hi3670_is_abbclk_seleted(priv)) {
> +		/* usb refclk iso disable */
> +		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
> +				   USB_REFCLK_ISO_EN);
> +		if (ret)
> +			goto out;
> +
> +		/* enable usb_tcxo_en */
> +		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
> +				   USB_TCXO_EN |
> +				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
> +
> +		/* select usbphy clk from abb */
> +		mask = SC_CLK_USB3PHY_3MUX1_SEL;
> +		ret = regmap_update_bits(priv->pctrl,
> +					 PCTRL_PERI_CTRL24, mask, 0);
> +		if (ret)
> +			goto out;
> +
> +		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
> +					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
> +		if (ret)
> +			goto out;
> +
> +		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
> +		if (ret)
> +			goto out;
> +		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
> +		val |= CTRL7_USB2_REFCLKSEL_ABB;
> +		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
> +		if (ret)
> +			goto out;
> +
> +		return 0;
> +	}
> +
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
> +				 CFG54_USB3PHY_REF_USE_PAD,
> +				 CFG54_USB3PHY_REF_USE_PAD);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
> +				 CFGA0_USB2PHY_REFCLK_SELECT,
> +				 CFGA0_USB2PHY_REFCLK_SELECT);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
> +	if (ret)
> +		goto out;
> +	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
> +	val |= CTRL7_USB2_REFCLKSEL_PAD;
> +	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(priv->peri_crg,
> +			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
> +	if (ret)
> +		goto out;
> +
> +	return 0;
> +out:
> +	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
> +	return ret;
> +}
> +
> +static int hi3670_config_tca(struct hi3670_priv *priv)
> +{
> +	u32 val, mask;
> +	int ret;
> +
> +	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
> +			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
> +	if (ret)
> +		goto out;
> +
> +	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
> +	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
> +				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
> +				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
> +				 SYSMODE_CFG_TYPEC_DISABLE, 0);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
> +	if (ret)
> +		goto out;
> +	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
> +	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
> +	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
> +			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
> +	if (ret)
> +		goto out;
> +
> +	return 0;
> +out:
> +	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
> +	return ret;
> +}
> +
> +static int hi3670_phy_init(struct phy *phy)
> +{
> +	struct hi3670_priv *priv = phy_get_drvdata(phy);
> +	u32 val;
> +	int ret;
> +
> +	/* assert controller */
> +	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
> +	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
> +	if (ret)
> +		goto out;
> +
> +	ret = hi3670_config_phy_clock(priv);
> +	if (ret)
> +		goto out;
> +
> +	/* Exit from IDDQ mode */
> +	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
> +				 CTRL5_USB2_SIDDQ, 0);
> +	if (ret)
> +		goto out;
> +
> +	/* Release USB31 PHY out of TestPowerDown mode */
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
> +				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
> +	if (ret)
> +		goto out;
> +
> +	/* Deassert phy */
> +	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
> +	if (ret)
> +		goto out;
> +
> +	usleep_range(100, 120);
> +
> +	/* Tell the PHY power is stable */
> +	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
> +	      CFG54_PHY0_PMA_PWR_STABLE;
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
> +				 val, val);
> +	if (ret)
> +		goto out;
> +
> +	ret = hi3670_config_tca(priv);
> +	if (ret)
> +		goto out;
> +
> +	/* Enable SSC */
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
> +				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
> +				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
> +	if (ret)
> +		goto out;
> +
> +	/* Deassert controller */
> +	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
> +	if (ret)
> +		goto out;
> +
> +	usleep_range(100, 120);
> +
> +	/* Set fake vbus valid signal */
> +	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
> +	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
> +	if (ret)
> +		goto out;
> +
> +	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
> +	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
> +	if (ret)
> +		goto out;
> +
> +	usleep_range(100, 120);
> +
> +	ret = hi3670_phy_set_params(priv);
> +	if (ret)
> +		goto out;
> +
> +	return 0;
> +out:
> +	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
> +	return ret;
> +}
> +
> +static int hi3670_phy_exit(struct phy *phy)
> +{
> +	struct hi3670_priv *priv = phy_get_drvdata(phy);
> +	u32 mask;
> +	int ret;
> +
> +	/* Assert phy */
> +	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> +	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
> +	if (ret)
> +		goto out;
> +
> +	if (hi3670_is_abbclk_seleted(priv)) {
> +		/* disable usb_tcxo_en */
> +		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
> +				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
> +	} else {
> +		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
> +				   GT_CLK_USB2PHY_REF);
> +		if (ret)
> +			goto out;
> +	}
> +
> +	return 0;
> +out:
> +	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
> +	return ret;
> +}
> +
> +static struct phy_ops hi3670_phy_ops = {
> +	.init		= hi3670_phy_init,
> +	.exit		= hi3670_phy_exit,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static int hi3670_phy_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *phy_provider;
> +	struct device *dev = &pdev->dev;
> +	struct phy *phy;
> +	struct hi3670_priv *priv;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
> +							 "hisilicon,pericrg-syscon");
> +	if (IS_ERR(priv->peri_crg)) {
> +		dev_err(dev, "no hisilicon,pericrg-syscon\n");
> +		return PTR_ERR(priv->peri_crg);
> +	}
> +
> +	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
> +						      "hisilicon,pctrl-syscon");
> +	if (IS_ERR(priv->pctrl)) {
> +		dev_err(dev, "no hisilicon,pctrl-syscon\n");
> +		return PTR_ERR(priv->pctrl);
> +	}
> +
> +	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
> +						      "hisilicon,sctrl-syscon");
> +	if (IS_ERR(priv->sctrl)) {
> +		dev_err(dev, "no hisilicon,sctrl-syscon\n");
> +		return PTR_ERR(priv->sctrl);
> +	}
> +
> +	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
> +	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(priv->usb31misc)) {
> +		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
> +		return PTR_ERR(priv->usb31misc);
> +	}
> +
> +	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
> +				 &priv->eye_diagram_param))
> +		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
> +
> +	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
> +				 &priv->tx_vboost_lvl))
> +		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
> +
> +	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
> +	if (IS_ERR(phy))
> +		return PTR_ERR(phy);
> +
> +	phy_set_drvdata(phy, priv);
> +	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +	return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id hi3670_phy_of_match[] = {
> +	{ .compatible = "hisilicon,hi3670-usb-phy" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
> +
> +static struct platform_driver hi3670_phy_driver = {
> +	.probe	= hi3670_phy_probe,
> +	.driver = {
> +		.name	= "hi3670-usb-phy",
> +		.of_match_table	= hi3670_phy_of_match,
> +	}
> +};
> +module_platform_driver(hi3670_phy_driver);
> +
> +MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
> diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
> index b29f5d5df134..0e97b5b9a56a 100644
> --- a/drivers/staging/hikey9xx/Kconfig
> +++ b/drivers/staging/hikey9xx/Kconfig
> @@ -1,16 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
>  
> -# to be placed at drivers/phy
> -config PHY_HI3670_USB
> -	tristate "hi3670 USB PHY support"
> -	depends on (ARCH_HISI && ARM64) || COMPILE_TEST
> -	select GENERIC_PHY
> -	select MFD_SYSCON
> -	help
> -	  Enable this to support the HISILICON HI3670 USB PHY.
> -
> -	  To compile this driver as a module, choose M here.
> -
>  # to be placed at drivers/spmi
>  config SPMI_HISI3670
>  	tristate "Hisilicon 3670 SPMI Controller"
> diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
> index 1924fadac952..9371dcc3d35b 100644
> --- a/drivers/staging/hikey9xx/Makefile
> +++ b/drivers/staging/hikey9xx/Makefile
> @@ -1,7 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
>  
> -obj-$(CONFIG_PHY_HI3670_USB)		+= phy-hi3670-usb3.o
> -
>  obj-$(CONFIG_SPMI_HISI3670)		+= hisi-spmi-controller.o
>  obj-$(CONFIG_MFD_HI6421_SPMI)		+= hi6421-spmi-pmic.o
>  obj-$(CONFIG_REGULATOR_HI6421V600)	+= hi6421v600-regulator.o
> diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.c b/drivers/staging/hikey9xx/phy-hi3670-usb3.c
> deleted file mode 100644
> index 4fc013911a78..000000000000
> --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.c
> +++ /dev/null
> @@ -1,671 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
> - *
> - * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
> - *		http://www.huawei.com
> - *
> - * Authors: Yu Chen <chenyu56@huawei.com>
> - */
> -
> -#include <linux/clk.h>
> -#include <linux/kernel.h>
> -#include <linux/mfd/syscon.h>
> -#include <linux/module.h>
> -#include <linux/phy/phy.h>
> -#include <linux/platform_device.h>
> -#include <linux/regmap.h>
> -
> -#define SCTRL_SCDEEPSLEEPED		(0x0)
> -#define USB_CLK_SELECTED		BIT(20)
> -
> -#define PERI_CRG_PEREN0			(0x00)
> -#define PERI_CRG_PERDIS0		(0x04)
> -#define PERI_CRG_PEREN4			(0x40)
> -#define PERI_CRG_PERDIS4		(0x44)
> -#define PERI_CRG_PERRSTEN4		(0x90)
> -#define PERI_CRG_PERRSTDIS4		(0x94)
> -#define PERI_CRG_ISODIS			(0x148)
> -#define PERI_CRG_PEREN6			(0x410)
> -#define PERI_CRG_PERDIS6		(0x414)
> -
> -#define USB_REFCLK_ISO_EN		BIT(25)
> -
> -#define GT_CLK_USB2PHY_REF		BIT(19)
> -
> -#define PCTRL_PERI_CTRL3		(0x10)
> -#define PCTRL_PERI_CTRL3_MSK_START	(16)
> -#define USB_TCXO_EN			BIT(1)
> -
> -#define PCTRL_PERI_CTRL24		(0x64)
> -#define SC_CLK_USB3PHY_3MUX1_SEL	BIT(25)
> -
> -#define USB3OTG_CTRL0			(0x00)
> -#define USB3OTG_CTRL3			(0x0C)
> -#define USB3OTG_CTRL4			(0x10)
> -#define USB3OTG_CTRL5			(0x14)
> -#define USB3OTG_CTRL7			(0x1C)
> -#define USB_MISC_CFG50			(0x50)
> -#define USB_MISC_CFG54			(0x54)
> -#define USB_MISC_CFG58			(0x58)
> -#define USB_MISC_CFG5C			(0x5C)
> -#define USB_MISC_CFGA0			(0xA0)
> -#define TCA_CLK_RST			(0x200)
> -#define TCA_INTR_EN			(0x204)
> -#define TCA_INTR_STS			(0x208)
> -#define TCA_GCFG			(0x210)
> -#define TCA_TCPC			(0x214)
> -#define TCA_SYSMODE_CFG			(0x218)
> -#define TCA_VBUS_CTRL			(0x240)
> -
> -#define CTRL0_USB3_VBUSVLD		BIT(7)
> -#define CTRL0_USB3_VBUSVLD_SEL		BIT(6)
> -
> -#define CTRL3_USB2_VBUSVLDEXT0		BIT(6)
> -#define CTRL3_USB2_VBUSVLDEXTSEL0	BIT(5)
> -
> -#define CTRL5_USB2_SIDDQ		BIT(0)
> -
> -#define CTRL7_USB2_REFCLKSEL_MASK	(3 << 3)
> -#define CTRL7_USB2_REFCLKSEL_ABB	(3 << 3)
> -#define CTRL7_USB2_REFCLKSEL_PAD	(2 << 3)
> -
> -#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
> -
> -#define CFG54_USB31PHY_CR_ADDR_MASK	(0xFFFF)
> -#define CFG54_USB31PHY_CR_ADDR_SHIFT	(16)
> -#define CFG54_USB3PHY_REF_USE_PAD	BIT(12)
> -#define CFG54_PHY0_PMA_PWR_STABLE	BIT(11)
> -#define CFG54_PHY0_PCS_PWR_STABLE	BIT(9)
> -#define CFG54_USB31PHY_CR_ACK		BIT(7)
> -#define CFG54_USB31PHY_CR_WR_EN		BIT(5)
> -#define CFG54_USB31PHY_CR_SEL		BIT(4)
> -#define CFG54_USB31PHY_CR_RD_EN		BIT(3)
> -#define CFG54_USB31PHY_CR_CLK		BIT(2)
> -#define CFG54_USB3_PHY0_ANA_PWR_EN	BIT(1)
> -
> -#define CFG58_USB31PHY_CR_DATA_MASK     (0xFFFF)
> -#define CFG58_USB31PHY_CR_DATA_RD_START (16)
> -
> -#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN	BIT(1)
> -
> -#define CFGA0_VAUX_RESET		BIT(9)
> -#define CFGA0_USB31C_RESET		BIT(8)
> -#define CFGA0_USB2PHY_REFCLK_SELECT	BIT(4)
> -#define CFGA0_USB3PHY_RESET		BIT(1)
> -#define CFGA0_USB2PHY_POR		BIT(0)
> -
> -#define INTR_EN_XA_TIMEOUT_EVT_EN	BIT(1)
> -#define INTR_EN_XA_ACK_EVT_EN		BIT(0)
> -
> -#define CLK_RST_TCA_REF_CLK_EN		BIT(1)
> -#define CLK_RST_SUSPEND_CLK_EN		BIT(0)
> -
> -#define GCFG_ROLE_HSTDEV		BIT(4)
> -#define GCFG_OP_MODE			(3 << 0)
> -#define GCFG_OP_MODE_CTRL_SYNC_MODE	BIT(0)
> -
> -#define TCPC_VALID			BIT(4)
> -#define TCPC_LOW_POWER_EN		BIT(3)
> -#define TCPC_MUX_CONTROL_MASK		(3 << 0)
> -#define TCPC_MUX_CONTROL_USB31		BIT(0)
> -
> -#define SYSMODE_CFG_TYPEC_DISABLE	BIT(3)
> -
> -#define VBUS_CTRL_POWERPRESENT_OVERRD	(3 << 2)
> -#define VBUS_CTRL_VBUSVALID_OVERRD	(3 << 0)
> -
> -#define KIRIN970_USB_DEFAULT_PHY_PARAM	(0xFDFEE4)
> -#define KIRIN970_USB_DEFAULT_PHY_VBOOST	(0x5)
> -
> -#define TX_VBOOST_LVL_REG		(0xf)
> -#define TX_VBOOST_LVL_START		(6)
> -#define TX_VBOOST_LVL_ENABLE		BIT(9)
> -
> -struct hi3670_priv {
> -	struct device *dev;
> -	struct regmap *peri_crg;
> -	struct regmap *pctrl;
> -	struct regmap *sctrl;
> -	struct regmap *usb31misc;
> -
> -	u32 eye_diagram_param;
> -	u32 tx_vboost_lvl;
> -
> -	u32 peri_crg_offset;
> -	u32 pctrl_offset;
> -	u32 usb31misc_offset;
> -};
> -
> -static int hi3670_phy_cr_clk(struct regmap *usb31misc)
> -{
> -	int ret;
> -
> -	/* Clock up */
> -	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -				 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
> -	if (ret)
> -		return ret;
> -
> -	/* Clock down */
> -	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -				 CFG54_USB31PHY_CR_CLK, 0);
> -
> -	return ret;
> -}
> -
> -static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
> -{
> -	return regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -				  CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
> -}
> -
> -static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
> -{
> -	int ret;
> -
> -	if (direction)
> -		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -					 CFG54_USB31PHY_CR_WR_EN,
> -					 CFG54_USB31PHY_CR_WR_EN);
> -	else
> -		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -					 CFG54_USB31PHY_CR_RD_EN,
> -					 CFG54_USB31PHY_CR_RD_EN);
> -
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_clk(usb31misc);
> -	if (ret)
> -		return ret;
> -
> -	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> -				 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
> -
> -	return ret;
> -}
> -
> -static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
> -{
> -	u32 reg;
> -	int retry = 100000;
> -	int ret;
> -
> -	while (retry-- > 0) {
> -		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> -		if (ret)
> -			return ret;
> -		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
> -			return 0;
> -
> -		ret = hi3670_phy_cr_clk(usb31misc);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	return -ETIMEDOUT;
> -}
> -
> -static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
> -{
> -	u32 reg;
> -	int ret;
> -
> -	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> -	if (ret)
> -		return ret;
> -
> -	reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT);
> -	reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT);
> -	ret = regmap_write(usb31misc, USB_MISC_CFG54, reg);
> -
> -	return ret;
> -}
> -
> -static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
> -{
> -	int reg;
> -	int i;
> -	int ret;
> -
> -	for (i = 0; i < 100; i++) {
> -		ret = hi3670_phy_cr_clk(usb31misc);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	ret = hi3670_phy_cr_set_sel(usb31misc);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_start(usb31misc, 0);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_wait_ack(usb31misc);
> -	if (ret)
> -		return ret;
> -
> -	ret = regmap_read(usb31misc, USB_MISC_CFG58, &reg);
> -	if (ret)
> -		return ret;
> -
> -	*val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) &
> -		CFG58_USB31PHY_CR_DATA_MASK;
> -
> -	return 0;
> -}
> -
> -static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
> -{
> -	int i;
> -	int ret;
> -
> -	for (i = 0; i < 100; i++) {
> -		ret = hi3670_phy_cr_clk(usb31misc);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	ret = hi3670_phy_cr_set_sel(usb31misc);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_set_addr(usb31misc, addr);
> -	if (ret)
> -		return ret;
> -
> -	ret = regmap_write(usb31misc, USB_MISC_CFG58,
> -			   val & CFG58_USB31PHY_CR_DATA_MASK);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_start(usb31misc, 1);
> -	if (ret)
> -		return ret;
> -
> -	ret = hi3670_phy_cr_wait_ack(usb31misc);
> -
> -	return ret;
> -}
> -
> -static int hi3670_phy_set_params(struct hi3670_priv *priv)
> -{
> -	u32 reg;
> -	int ret;
> -	int retry = 3;
> -
> -	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4,
> -			   priv->eye_diagram_param);
> -	if (ret) {
> -		dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
> -		return ret;
> -	}
> -
> -	while (retry-- > 0) {
> -		ret = hi3670_phy_cr_read(priv->usb31misc,
> -					 TX_VBOOST_LVL_REG, &reg);
> -		if (!ret)
> -			break;
> -
> -		if (ret != -ETIMEDOUT) {
> -			dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
> -			return ret;
> -		}
> -	}
> -	if (ret)
> -		return ret;
> -
> -	reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
> -	ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg);
> -	if (ret)
> -		dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
> -
> -	return ret;
> -}
> -
> -static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv)
> -{
> -	u32 reg;
> -
> -	if (!priv->sctrl) {
> -		dev_err(priv->dev, "priv->sctrl is null!\n");
> -		return 1;
> -	}
> -
> -	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
> -		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
> -		return 1;
> -	}
> -
> -	if ((reg & USB_CLK_SELECTED) == 0)
> -		return 1;
> -
> -	return 0;
> -}
> -
> -static int hi3670_config_phy_clock(struct hi3670_priv *priv)
> -{
> -	u32 val, mask;
> -	int ret;
> -
> -	if (hi3670_is_abbclk_seleted(priv)) {
> -		/* usb refclk iso disable */
> -		ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS,
> -				   USB_REFCLK_ISO_EN);
> -		if (ret)
> -			goto out;
> -
> -		/* enable usb_tcxo_en */
> -		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
> -				   USB_TCXO_EN |
> -				   (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
> -
> -		/* select usbphy clk from abb */
> -		mask = SC_CLK_USB3PHY_3MUX1_SEL;
> -		ret = regmap_update_bits(priv->pctrl,
> -					 PCTRL_PERI_CTRL24, mask, 0);
> -		if (ret)
> -			goto out;
> -
> -		ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
> -					 CFGA0_USB2PHY_REFCLK_SELECT, 0);
> -		if (ret)
> -			goto out;
> -
> -		ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
> -		if (ret)
> -			goto out;
> -		val &= ~CTRL7_USB2_REFCLKSEL_MASK;
> -		val |= CTRL7_USB2_REFCLKSEL_ABB;
> -		ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
> -		if (ret)
> -			goto out;
> -
> -		return 0;
> -	}
> -
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
> -				 CFG54_USB3PHY_REF_USE_PAD,
> -				 CFG54_USB3PHY_REF_USE_PAD);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0,
> -				 CFGA0_USB2PHY_REFCLK_SELECT,
> -				 CFGA0_USB2PHY_REFCLK_SELECT);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val);
> -	if (ret)
> -		goto out;
> -	val &= ~CTRL7_USB2_REFCLKSEL_MASK;
> -	val |= CTRL7_USB2_REFCLKSEL_PAD;
> -	ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_write(priv->peri_crg,
> -			   PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
> -	if (ret)
> -		goto out;
> -
> -	return 0;
> -out:
> -	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
> -	return ret;
> -}
> -
> -static int hi3670_config_tca(struct hi3670_priv *priv)
> -{
> -	u32 val, mask;
> -	int ret;
> -
> -	ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_write(priv->usb31misc, TCA_INTR_EN,
> -			   INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
> -	if (ret)
> -		goto out;
> -
> -	mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
> -	ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_update_bits(priv->usb31misc, TCA_GCFG,
> -				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
> -				 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG,
> -				 SYSMODE_CFG_TYPEC_DISABLE, 0);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_read(priv->usb31misc, TCA_TCPC, &val);
> -	if (ret)
> -		goto out;
> -	val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
> -	val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
> -	ret = regmap_write(priv->usb31misc, TCA_TCPC, val);
> -	if (ret)
> -		goto out;
> -
> -	ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL,
> -			   VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
> -	if (ret)
> -		goto out;
> -
> -	return 0;
> -out:
> -	dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
> -	return ret;
> -}
> -
> -static int hi3670_phy_init(struct phy *phy)
> -{
> -	struct hi3670_priv *priv = phy_get_drvdata(phy);
> -	u32 val;
> -	int ret;
> -
> -	/* assert controller */
> -	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
> -	      CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0);
> -	if (ret)
> -		goto out;
> -
> -	ret = hi3670_config_phy_clock(priv);
> -	if (ret)
> -		goto out;
> -
> -	/* Exit from IDDQ mode */
> -	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5,
> -				 CTRL5_USB2_SIDDQ, 0);
> -	if (ret)
> -		goto out;
> -
> -	/* Release USB31 PHY out of TestPowerDown mode */
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50,
> -				 CFG50_USB3_PHY_TEST_POWERDOWN, 0);
> -	if (ret)
> -		goto out;
> -
> -	/* Deassert phy */
> -	val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
> -	if (ret)
> -		goto out;
> -
> -	usleep_range(100, 120);
> -
> -	/* Tell the PHY power is stable */
> -	val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
> -	      CFG54_PHY0_PMA_PWR_STABLE;
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54,
> -				 val, val);
> -	if (ret)
> -		goto out;
> -
> -	ret = hi3670_config_tca(priv);
> -	if (ret)
> -		goto out;
> -
> -	/* Enable SSC */
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C,
> -				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
> -				 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
> -	if (ret)
> -		goto out;
> -
> -	/* Deassert controller */
> -	val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val);
> -	if (ret)
> -		goto out;
> -
> -	usleep_range(100, 120);
> -
> -	/* Set fake vbus valid signal */
> -	val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
> -	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val);
> -	if (ret)
> -		goto out;
> -
> -	val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
> -	ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val);
> -	if (ret)
> -		goto out;
> -
> -	usleep_range(100, 120);
> -
> -	ret = hi3670_phy_set_params(priv);
> -	if (ret)
> -		goto out;
> -
> -	return 0;
> -out:
> -	dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
> -	return ret;
> -}
> -
> -static int hi3670_phy_exit(struct phy *phy)
> -{
> -	struct hi3670_priv *priv = phy_get_drvdata(phy);
> -	u32 mask;
> -	int ret;
> -
> -	/* Assert phy */
> -	mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
> -	ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0);
> -	if (ret)
> -		goto out;
> -
> -	if (hi3670_is_abbclk_seleted(priv)) {
> -		/* disable usb_tcxo_en */
> -		ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3,
> -				   USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
> -	} else {
> -		ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6,
> -				   GT_CLK_USB2PHY_REF);
> -		if (ret)
> -			goto out;
> -	}
> -
> -	return 0;
> -out:
> -	dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
> -	return ret;
> -}
> -
> -static struct phy_ops hi3670_phy_ops = {
> -	.init		= hi3670_phy_init,
> -	.exit		= hi3670_phy_exit,
> -	.owner		= THIS_MODULE,
> -};
> -
> -static int hi3670_phy_probe(struct platform_device *pdev)
> -{
> -	struct phy_provider *phy_provider;
> -	struct device *dev = &pdev->dev;
> -	struct phy *phy;
> -	struct hi3670_priv *priv;
> -
> -	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv)
> -		return -ENOMEM;
> -
> -	priv->dev = dev;
> -	priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node,
> -							 "hisilicon,pericrg-syscon");
> -	if (IS_ERR(priv->peri_crg)) {
> -		dev_err(dev, "no hisilicon,pericrg-syscon\n");
> -		return PTR_ERR(priv->peri_crg);
> -	}
> -
> -	priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
> -						      "hisilicon,pctrl-syscon");
> -	if (IS_ERR(priv->pctrl)) {
> -		dev_err(dev, "no hisilicon,pctrl-syscon\n");
> -		return PTR_ERR(priv->pctrl);
> -	}
> -
> -	priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
> -						      "hisilicon,sctrl-syscon");
> -	if (IS_ERR(priv->sctrl)) {
> -		dev_err(dev, "no hisilicon,sctrl-syscon\n");
> -		return PTR_ERR(priv->sctrl);
> -	}
> -
> -	/* node of hi3670 phy is a sub-node of usb3_otg_bc */
> -	priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node);
> -	if (IS_ERR(priv->usb31misc)) {
> -		dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
> -		return PTR_ERR(priv->usb31misc);
> -	}
> -
> -	if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param",
> -				 &priv->eye_diagram_param))
> -		priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
> -
> -	if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl",
> -				 &priv->tx_vboost_lvl))
> -		priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
> -
> -	phy = devm_phy_create(dev, NULL, &hi3670_phy_ops);
> -	if (IS_ERR(phy))
> -		return PTR_ERR(phy);
> -
> -	phy_set_drvdata(phy, priv);
> -	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> -	return PTR_ERR_OR_ZERO(phy_provider);
> -}
> -
> -static const struct of_device_id hi3670_phy_of_match[] = {
> -	{ .compatible = "hisilicon,hi3670-usb-phy" },
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
> -
> -static struct platform_driver hi3670_phy_driver = {
> -	.probe	= hi3670_phy_probe,
> -	.driver = {
> -		.name	= "hi3670-usb-phy",
> -		.of_match_table	= hi3670_phy_of_match,
> -	}
> -};
> -module_platform_driver(hi3670_phy_driver);
> -
> -MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
> -MODULE_LICENSE("GPL v2");
> -MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
> diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml b/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
> deleted file mode 100644
> index 125a5d6546ae..000000000000
> --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
> +++ /dev/null
> @@ -1,72 +0,0 @@
> -# SPDX-License-Identifier: GPL-2.0
> -%YAML 1.2
> ----
> -$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml#
> -$schema: http://devicetree.org/meta-schemas/core.yaml#
> -
> -title: Hisilicon Kirin970 USB PHY
> -
> -maintainers:
> -  - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> -description: |+
> -  Bindings for USB3 PHY on HiSilicon Kirin 970.
> -
> -properties:
> -  compatible:
> -    const: hisilicon,hi3670-usb-phy
> -
> -  "#phy-cells":
> -    const: 0
> -
> -  hisilicon,pericrg-syscon:
> -    $ref: '/schemas/types.yaml#/definitions/phandle'
> -    description: phandle of syscon used to control iso refclk.
> -
> -  hisilicon,pctrl-syscon:
> -    $ref: '/schemas/types.yaml#/definitions/phandle'
> -    description: phandle of syscon used to control usb tcxo.
> -
> -  hisilicon,sctrl-syscon:
> -    $ref: '/schemas/types.yaml#/definitions/phandle'
> -    description: phandle of syscon used to control phy deep sleep.
> -
> -  hisilicon,eye-diagram-param:
> -    $ref: /schemas/types.yaml#/definitions/uint32
> -    description: Eye diagram for phy.
> -
> -  hisilicon,tx-vboost-lvl:
> -    $ref: /schemas/types.yaml#/definitions/uint32
> -    description: TX level vboost for phy.
> -
> -required:
> -  - compatible
> -  - hisilicon,pericrg-syscon
> -  - hisilicon,pctrl-syscon
> -  - hisilicon,sctrl-syscon
> -  - hisilicon,eye-diagram-param
> -  - hisilicon,tx-vboost-lvl
> -  - "#phy-cells"
> -
> -additionalProperties: false
> -
> -examples:
> -  - |
> -    bus {
> -      #address-cells = <2>;
> -      #size-cells = <2>;
> -
> -      usb3_otg_bc: usb3_otg_bc@ff200000 {
> -        compatible = "syscon", "simple-mfd";
> -        reg = <0x0 0xff200000 0x0 0x1000>;
> -
> -        usb_phy {
> -          compatible = "hisilicon,hi3670-usb-phy";
> -          #phy-cells = <0>;
> -          hisilicon,pericrg-syscon = <&crg_ctrl>;
> -          hisilicon,pctrl-syscon = <&pctrl>;
> -          hisilicon,sctrl-syscon = <&sctrl>;
> -          hisilicon,eye-diagram-param = <0xfdfee4>;
> -          hisilicon,tx-vboost-lvl = <0x5>;
> -        };
> -      };
> -    };
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
  2020-11-16 15:31   ` Rob Herring
@ 2020-11-16 15:31   ` Rob Herring
  2020-11-30 10:30   ` Vinod Koul
  2 siblings, 0 replies; 21+ messages in thread
From: Rob Herring @ 2020-11-16 15:31 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Manivannan Sadhasivam, Greg Kroah-Hartman, John Stultz,
	mauro.chehab, devel, Vinod Koul, Alex Dewar, linuxarm,
	Krzysztof Kozlowski, linux-kernel, Yu Chen, devicetree,
	Kishon Vijay Abraham I, Rob Herring

On Mon, 16 Nov 2020 13:59:27 +0100, Mauro Carvalho Chehab wrote:
> The phy USB3 driver for Hisilicon 970 (hi3670) is ready
> for mainstream. Mode it from staging into the main driver's
> phy/ directory.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
>  MAINTAINERS                                   |   9 +-
>  drivers/phy/hisilicon/Kconfig                 |  10 +
>  drivers/phy/hisilicon/Makefile                |   1 +
>  drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
>  drivers/staging/hikey9xx/Kconfig              |  11 -
>  drivers/staging/hikey9xx/Makefile             |   2 -
>  drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
>  drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --
>  9 files changed, 762 insertions(+), 757 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml
>  create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c
>  delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c
>  delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml
> 


My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
./Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml: $id: relative path/filename doesn't match actual path or filename
	expected: http://devicetree.org/schemas/phy/phy-hi3670-usb3.yaml#


See https://patchwork.ozlabs.org/patch/1400895

The base for the patch is generally the last rc1. Any dependencies
should be noted.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging
  2020-11-16 12:59 ` [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging Mauro Carvalho Chehab
@ 2020-11-16 15:32   ` Rob Herring
  0 siblings, 0 replies; 21+ messages in thread
From: Rob Herring @ 2020-11-16 15:32 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, YueHaibing, mauro.chehab, Dan Carpenter,
	linux-kernel, linuxarm, devicetree, John Stultz, linux-arm-msm,
	Colin Ian King, Greg Kroah-Hartman, Mayulong,
	Manivannan Sadhasivam, Stephen Boyd, devel

On Mon, 16 Nov 2020 13:59:28 +0100, Mauro Carvalho Chehab wrote:
> The Hisilicon 6421v600 SPMI driver is ready for mainstream.
> 
> So, move it from staging.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  .../spmi/hisilicon,hisi-spmi-controller.yaml  |  62 +++
>  MAINTAINERS                                   |   7 +
>  drivers/spmi/Kconfig                          |   9 +
>  drivers/spmi/Makefile                         |   1 +
>  drivers/spmi/hisi-spmi-controller.c           | 358 ++++++++++++++++++
>  drivers/staging/hikey9xx/Kconfig              |  11 -
>  drivers/staging/hikey9xx/Makefile             |   1 -
>  .../staging/hikey9xx/hisi-spmi-controller.c   | 358 ------------------
>  .../hisilicon,hisi-spmi-controller.yaml       |  62 ---
>  9 files changed, 437 insertions(+), 432 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
>  create mode 100644 drivers/spmi/hisi-spmi-controller.c
>  delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
>  delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
> 


My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml:34:2: [warning] wrong indentation: expected 2 but found 1 (indentation)

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml: 'additionalProperties' is a required property
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml: ignoring, error in schema: 
warning: no schema found in file: ./Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dts:29.20-31.15: Warning (unit_address_vs_reg): /example-0/bus/spmi@fff24000/pmic@0: node has a unit name, but no reg or ranges property
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: spmi@fff24000: pmic@0: 'reg' is a required property
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/spmi.yaml


See https://patchwork.ozlabs.org/patch/1400897

The base for the patch is generally the last rc1. Any dependencies
should be noted.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/8] mfd: hi6421-spmi-pmic: move driver from staging
  2020-11-16 12:59 ` [PATCH 3/8] mfd: " Mauro Carvalho Chehab
@ 2020-11-16 15:32   ` Rob Herring
  0 siblings, 0 replies; 21+ messages in thread
From: Rob Herring @ 2020-11-16 15:32 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Mayulong, devicetree, John Stultz, Lee Jones, Rob Herring,
	linuxarm, Greg Kroah-Hartman, devel, mauro.chehab,
	Manivannan Sadhasivam, linux-kernel

On Mon, 16 Nov 2020 13:59:29 +0100, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 159 ++++++++
>  MAINTAINERS                                   |   7 +
>  drivers/mfd/Kconfig                           |  15 +
>  drivers/mfd/Makefile                          |   1 +
>  drivers/mfd/hi6421-spmi-pmic.c                | 342 ++++++++++++++++++
>  drivers/staging/hikey9xx/Kconfig              |  16 -
>  drivers/staging/hikey9xx/Makefile             |   1 -
>  drivers/staging/hikey9xx/hi6421-spmi-pmic.c   | 342 ------------------
>  .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml  | 159 --------
>  9 files changed, 524 insertions(+), 518 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
>  create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
>  delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
>  delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
> 


My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: 'additionalProperties' is a required property
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: ignoring, error in schema: 
warning: no schema found in file: ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml


See https://patchwork.ozlabs.org/patch/1400898

The base for the patch is generally the last rc1. Any dependencies
should be noted.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-16 12:59 ` [PATCH 4/8] regulator: hi6421v600-regulator: move it " Mauro Carvalho Chehab
@ 2020-11-16 18:38   ` Mark Brown
  2020-11-17  8:08     ` Mauro Carvalho Chehab
  2020-11-17  8:38     ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 21+ messages in thread
From: Mark Brown @ 2020-11-16 18:38 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, John Stultz, Manivannan Sadhasivam,
	Greg Kroah-Hartman, Liam Girdwood, Mayulong, YueHaibing, devel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 7179 bytes --]

On Mon, Nov 16, 2020 at 01:59:30PM +0100, Mauro Carvalho Chehab wrote:

> This driver is ready for mainstream. Move it out of staging.

There's quite a few issues here, to be honest I'm disappointed some of
them weren't caught during staging review, this needs fairly substantial
work and there's signs that this also applies to at least the MFD
portion.

This also appears to be missing a DT binding document, binding
documentation is required for anything with DT support.

> +config REGULATOR_HI6421V600
> +	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
> +	depends on MFD_HI6421_SPMI && OF
> +	depends on REGULATOR

This is inside an if REGULATOR block, as with all the other regulator
drivers it doesn't need a dependency on REGULATOR.

> --- /dev/null
> +++ b/drivers/regulator/hi6421v600-regulator.c
> @@ -0,0 +1,478 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Device driver for regulators in Hisi IC

Please make the entire comment a C++ one so things look more
intentional.

> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/mfd/hi6421-spmi-pmic.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/of_regulator.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>
> +#include <linux/spmi.h>
> +#include <linux/time.h>
> +#include <linux/uaccess.h>

Are we sure about *all* these includes?

> +#define rdev_dbg(rdev, fmt, arg...)	\
> +		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)

If it is useful to copy this then put it in a header rather than
cut'n'pasting it.  I'm not sure I see a pressing need for most of the
trace here, it looks to be duplicating a lot of things the core does for
you.

> +static DEFINE_MUTEX(enable_mutex);

Drivers shouldn't be declaring global variables, if this is required it
should be allocated in driver data.

> +/*
> + * helper function to ensure when it returns it is at least 'delay_us'
> + * microseconds after 'since'.
> + */
> +
> +static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)

The helper function appears to have been removed?

> +{
> +	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
> +	struct hi6421_spmi_pmic *pmic = sreg->pmic;
> +	u32 reg_val;
> +
> +	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
> +
> +	rdev_dbg(rdev,
> +		 "enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
> +		 rdev->desc->enable_reg,
> +		 reg_val, (reg_val & rdev->desc->enable_mask));
> +
> +	return ((reg_val & rdev->desc->enable_mask) != 0);
> +}

It looks like it would be less code overall to just implement a regmap
for the MFD, even if it were only used in this driver - almost
everything in here is just a carbon copy of standard helpers that the
core provides for regmap devices.  Doing it in the MFD would be more
idiomatic for everything though.

> +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
> +{
> +	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
> +	struct hi6421_spmi_pmic *pmic = sreg->pmic;
> +
> +	/* cannot enable more than one regulator at one time */
> +	mutex_lock(&enable_mutex);
> +	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
> +		     HISI_REGS_ENA_PROTECT_TIME + 1000);
> +
> +	/* set enable register */
> +	rdev_dbg(rdev,
> +		 "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n",
> +		 rdev->desc->off_on_delay, rdev->desc->enable_reg,
> +		 rdev->desc->enable_mask);
> +
> +	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
> +			     rdev->desc->enable_mask,
> +			     rdev->desc->enable_mask);

This is the one operation which is doing anything unusual and which I'd
expect to be open coded in the driver - obviously this is a pretty
simplistic implementation but it will work though as indicated above it
shouldn't be using a global, the mutex should be in driver data.  I
guess you could use the mutex to protect a timestamp and use that to
figure out if a delay is actually needed?

> +static int hi6421_spmi_dt_parse(struct platform_device *pdev,
> +				struct hi6421v600_regulator *sreg,
> +			 struct regulator_desc *rdesc)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	unsigned int *v_table;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, "reg", &rdesc->enable_reg);
> +	if (ret) {
> +		dev_err(dev, "missing reg property\n");
> +		return ret;
> +	}
> +
> +	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);

There is no way this stuff should be being parsed out of DT, we should
know the register map for the device and what regulators it has based
purely off knowing what device we have.  Baking the register map into
the ABI is bad practice, it prevents us from improving our support for
the hardware without going and updating people's DTs.

> +	/*
> +	 * Not all regulators work on idle mode
> +	 */
> +	ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask);
> +	if (ret) {
> +		dev_dbg(dev, "LDO doesn't support economy mode.\n");
> +		sreg->eco_mode_mask = 0;
> +		sreg->eco_uA = 0;
> +	} else {
> +		ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA);

There's no conditional code to not register the mode operations if the
mode information is not available (and again this should be done based 
on knowing the properties of the device, this is unlikely to be system
dependent).

> +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
> +                                          struct device_node *np,
> +                                          struct hi6421_spmi_pmic *pmic)
> +{

This probe code looks very different to other regulator drivers, this
alone should have been a warning that the driver needs some substantial
refactoring here.  As indicated information about what regulators are
present on devices and their properties should be in the driver not the
DT, the driver should just be able to register them unconditionally and
use of_match and regulators_node to allow the core to find any
constraints that are provided by the platform.

> +	constraint->valid_modes_mask = REGULATOR_MODE_NORMAL;
> +	if (sreg->eco_mode_mask) {
> +		constraint->valid_modes_mask |= REGULATOR_MODE_IDLE;
> +		constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE;
> +	}

This is absolutely not OK, a regulator driver should *not* be modifying
the constraints that the machine has set.  If it is safe to change modes
on a platform and the system integrator wants to do that then they will
set the constraints appropriately, there is no way the regulator driver
can tell what is appropriate on a given system.  The fact that the
driver is including machine.h at all ought to have been an indicator
that there's an abstraction problem here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-16 15:31   ` Rob Herring
@ 2020-11-17  6:55     ` Mauro Carvalho Chehab
  2020-11-17  9:51       ` Vinod Koul
  0 siblings, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-17  6:55 UTC (permalink / raw)
  To: Rob Herring
  Cc: Vinod Koul, linuxarm, mauro.chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Krzysztof Kozlowski, Yu Chen, devel,
	devicetree, linux-kernel

Em Mon, 16 Nov 2020 09:31:06 -0600
Rob Herring <robh@kernel.org> escreveu:

> On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote:
> > The phy USB3 driver for Hisilicon 970 (hi3670) is ready
> > for mainstream. Mode it from staging into the main driver's  
> 
> s/Mode/Move/
> 
> > phy/ directory.
> > 
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > ---
> >  .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
> >  MAINTAINERS                                   |   9 +-
> >  drivers/phy/hisilicon/Kconfig                 |  10 +
> >  drivers/phy/hisilicon/Makefile                |   1 +
> >  drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
> >  drivers/staging/hikey9xx/Kconfig              |  11 -
> >  drivers/staging/hikey9xx/Makefile             |   2 -
> >  drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
> >  drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --  
> 
> I assume this is only a move? Use '-M' option.

This is a move, although I explicitly disabled -M on this series, as both
the driver code and DT may still require some review, as those patches
are for subsystems that I haven't made any relevant contributions
so far.

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-16 18:38   ` Mark Brown
@ 2020-11-17  8:08     ` Mauro Carvalho Chehab
  2020-11-17 14:25       ` Mark Brown
  2020-11-17  8:38     ` Mauro Carvalho Chehab
  1 sibling, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-17  8:08 UTC (permalink / raw)
  To: Mark Brown
  Cc: linuxarm, mauro.chehab, John Stultz, Manivannan Sadhasivam,
	Greg Kroah-Hartman, Liam Girdwood, Mayulong, YueHaibing, devel,
	linux-kernel

Hi Mark,

Em Mon, 16 Nov 2020 18:38:33 +0000
Mark Brown <broonie@kernel.org> escreveu:

> > This driver is ready for mainstream. Move it out of staging.  
> 
> There's quite a few issues here, to be honest I'm disappointed some of
> them weren't caught during staging review, this needs fairly substantial
> work and there's signs that this also applies to at least the MFD
> portion.
> 
...
> > +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
> > +                                          struct device_node *np,
> > +                                          struct hi6421_spmi_pmic *pmic)
> > +{  
> 
> This probe code looks very different to other regulator drivers, this
> alone should have been a warning that the driver needs some substantial
> refactoring here.  As indicated information about what regulators are
> present on devices and their properties should be in the driver not the
> DT, the driver should just be able to register them unconditionally and
> use of_match and regulators_node to allow the core to find any
> constraints that are provided by the platform.

Let me reply to this before handling the other issues you pointed, as
this one is related to some design decisions I had to make for this driver
to properly work upstream.

FYI, all documentation I have about this board is at:
	https://www.96boards.org/documentation/consumer/hikey/hikey970/

-

The setup for MFD/regulator is different than almost all other
regulator drivers currently upstreamed[1]. 

The PM part of Hikey970 is based on a master/slave SPMI bus. Each
bus can have up to 16 PM chips connected into it.

It means that, for the regulator driver to work, two drivers
should be probed first: the SPMI bus controller driver
(hisi-spmi-controller.c) and the SPMI bus client driver, which is
at the MFD driver(hi6421-spmi-pmic.c).

Only after having both probed, the regulator driver can be
probed.

Also, as all the communication between the PM chip
and the SoC happens via a single serial bus, there's no
sense on probing the regulators in parallel.

That's mainly the reason why I opted to serialize the probe
inside hi6421v600-regulator.c. 

The relevant changeset that ensures that everything is
probed the right way is this one:
	75937f8f961e ("staging: regulator: hi6421v600-regulator: change the binding logic")

Without such change, the driver doesn't work upstream, as the 
regulator driver ends by being probed before the bus client
driver (MFD).

There's a second reason, though: when letting regulator probe to
happen in parallel, the LDOs got probed on a random order, which
makes more difficult to debug the driver, as the LDO numbering
may not be following the LDO name, making harder to debug the
drivers that depend on regulator support.

Thanks,
Mauro

[1] The only other drivers for SPMI bus are from some Qualcomm
based boards - those seem to be using a different setup.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-16 18:38   ` Mark Brown
  2020-11-17  8:08     ` Mauro Carvalho Chehab
@ 2020-11-17  8:38     ` Mauro Carvalho Chehab
  2020-11-17 15:10       ` Mark Brown
  1 sibling, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2020-11-17  8:38 UTC (permalink / raw)
  To: Mark Brown
  Cc: linuxarm, mauro.chehab, John Stultz, Manivannan Sadhasivam,
	Greg Kroah-Hartman, Liam Girdwood, Mayulong, YueHaibing, devel,
	linux-kernel

Em Mon, 16 Nov 2020 18:38:33 +0000
Mark Brown <broonie@kernel.org> escreveu:

> On Mon, Nov 16, 2020 at 01:59:30PM +0100, Mauro Carvalho Chehab wrote:
> 
> > This driver is ready for mainstream. Move it out of staging.  
> 
> There's quite a few issues here, to be honest I'm disappointed some of
> them weren't caught during staging review, this needs fairly substantial
> work and there's signs that this also applies to at least the MFD
> portion.
> 
> This also appears to be missing a DT binding document, binding
> documentation is required for anything with DT support.

The DT binding is documented on patch 3/8, together with MFD.

As there's just one compatible for MFD and regulators altogether,
I opted to have just one DT binding document for both.

> 
> > +config REGULATOR_HI6421V600
> > +	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
> > +	depends on MFD_HI6421_SPMI && OF
> > +	depends on REGULATOR  
> 
> This is inside an if REGULATOR block, as with all the other regulator
> drivers it doesn't need a dependency on REGULATOR.

I'll drop it. This was needed while this was inside staging.

> 
> > --- /dev/null
> > +++ b/drivers/regulator/hi6421v600-regulator.c
> > @@ -0,0 +1,478 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Device driver for regulators in Hisi IC  
> 
> Please make the entire comment a C++ one so things look more
> intentional.

Ok.

> 
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/hi6421-spmi-pmic.h>
> > +#include <linux/module.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/driver.h>
> > +#include <linux/regulator/machine.h>
> > +#include <linux/regulator/of_regulator.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/slab.h>
> > +#include <linux/spmi.h>
> > +#include <linux/time.h>
> > +#include <linux/uaccess.h>  
> 
> Are we sure about *all* these includes?

I'll double check and do some cleanups.

> 
> > +#define rdev_dbg(rdev, fmt, arg...)	\
> > +		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)  
> 
> If it is useful to copy this then put it in a header rather than
> cut'n'pasting it.  I'm not sure I see a pressing need for most of the
> trace here, it looks to be duplicating a lot of things the core does for
> you.

I'll cleanup the debug messages, and place this on a header.

Due to SPMI bus, the standard debug macros don't work fine on
this file.

> 
> > +static DEFINE_MUTEX(enable_mutex);  
> 
> Drivers shouldn't be declaring global variables, if this is required it
> should be allocated in driver data.

I'll try to see a better place for this, but in this case, the
mutex should be global anyway, as the access to the SPMI bus
should be serialized.

I suspect that a change like that will likely require touching
the SPMI bus core, but I can't foresee the side effects to the
Qualcomm SPMI drivers that would likely have their own ways
to serialize access to the bus.

> 
> > +/*
> > + * helper function to ensure when it returns it is at least 'delay_us'
> > + * microseconds after 'since'.
> > + */
> > +
> > +static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)  
> 
> The helper function appears to have been removed?

I'll drop the comment.

> 
> > +{
> > +	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
> > +	struct hi6421_spmi_pmic *pmic = sreg->pmic;
> > +	u32 reg_val;
> > +
> > +	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
> > +
> > +	rdev_dbg(rdev,
> > +		 "enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
> > +		 rdev->desc->enable_reg,
> > +		 reg_val, (reg_val & rdev->desc->enable_mask));
> > +
> > +	return ((reg_val & rdev->desc->enable_mask) != 0);
> > +}  
> 
> It looks like it would be less code overall to just implement a regmap
> for the MFD, even if it were only used in this driver - almost
> everything in here is just a carbon copy of standard helpers that the
> core provides for regmap devices.  Doing it in the MFD would be more
> idiomatic for everything though.

I tried to use regmap for this driver while porting it from Linaro's
OOT to upstream, but it turns that adding support for it is not trivial.

I suspect that, just like I2C has their own set of regmap functions
(regmap_init_i2c, devm_regmap_init_i2c), if we want to properly support
regmap, we need first to add a SPMI variant to it, as the locking
should be bus-aware.

> 
> > +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
> > +{
> > +	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
> > +	struct hi6421_spmi_pmic *pmic = sreg->pmic;
> > +
> > +	/* cannot enable more than one regulator at one time */
> > +	mutex_lock(&enable_mutex);
> > +	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
> > +		     HISI_REGS_ENA_PROTECT_TIME + 1000);
> > +
> > +	/* set enable register */
> > +	rdev_dbg(rdev,
> > +		 "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n",
> > +		 rdev->desc->off_on_delay, rdev->desc->enable_reg,
> > +		 rdev->desc->enable_mask);
> > +
> > +	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
> > +			     rdev->desc->enable_mask,
> > +			     rdev->desc->enable_mask);  
> 
> This is the one operation which is doing anything unusual and which I'd
> expect to be open coded in the driver - obviously this is a pretty
> simplistic implementation but it will work though as indicated above it
> shouldn't be using a global, the mutex should be in driver data.  I
> guess you could use the mutex to protect a timestamp and use that to
> figure out if a delay is actually needed?

I'll rework this logic.

> > +static int hi6421_spmi_dt_parse(struct platform_device *pdev,
> > +				struct hi6421v600_regulator *sreg,
> > +			 struct regulator_desc *rdesc)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *np = dev->of_node;
> > +	unsigned int *v_table;
> > +	int ret;
> > +
> > +	ret = of_property_read_u32(np, "reg", &rdesc->enable_reg);
> > +	if (ret) {
> > +		dev_err(dev, "missing reg property\n");
> > +		return ret;
> > +	}
> > +
> > +	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);  
> 
> There is no way this stuff should be being parsed out of DT, we should
> know the register map for the device and what regulators it has based
> purely off knowing what device we have.  Baking the register map into
> the ABI is bad practice, it prevents us from improving our support for
> the hardware without going and updating people's DTs.

Well, I can move the existing registers out of DT, but, as I don't
have any datasheet for this device, it means that I can implement
there only a subset of the available LDOs. So, from the 36 LDOs that
this chip support, we only know the registers for 8 of them:

	ldo3, ldo4, ldo9, ldo15, ldo16, ldo17, ldo33 and ldo34.

> > +	/*
> > +	 * Not all regulators work on idle mode
> > +	 */
> > +	ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask);
> > +	if (ret) {
> > +		dev_dbg(dev, "LDO doesn't support economy mode.\n");
> > +		sreg->eco_mode_mask = 0;
> > +		sreg->eco_uA = 0;
> > +	} else {
> > +		ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA);  
> 
> There's no conditional code to not register the mode operations if the
> mode information is not available (and again this should be done based 
> on knowing the properties of the device, this is unlikely to be system
> dependent).

This is the same case as before: as we don't have any datasheets,
I only know what's there at the DT for just one device (Hikey 970).

Again, we could hardcode those assuming Hikey 970 settings, but,
if some other device using the same chip will ever be added, and
they use some different configuration then we may face some
backward-compatibility issues.

> 
> > +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
> > +                                          struct device_node *np,
> > +                                          struct hi6421_spmi_pmic *pmic)
> > +{  
> 
> This probe code looks very different to other regulator drivers, this
> alone should have been a warning that the driver needs some substantial
> refactoring here.  As indicated information about what regulators are
> present on devices and their properties should be in the driver not the
> DT, the driver should just be able to register them unconditionally and
> use of_match and regulators_node to allow the core to find any
> constraints that are provided by the platform.

(already commented on a separate e-mail)

> 
> > +	constraint->valid_modes_mask = REGULATOR_MODE_NORMAL;
> > +	if (sreg->eco_mode_mask) {
> > +		constraint->valid_modes_mask |= REGULATOR_MODE_IDLE;
> > +		constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE;
> > +	}  
> 
> This is absolutely not OK, a regulator driver should *not* be modifying
> the constraints that the machine has set.  If it is safe to change modes
> on a platform and the system integrator wants to do that then they will
> set the constraints appropriately, there is no way the regulator driver
> can tell what is appropriate on a given system.  The fact that the
> driver is including machine.h at all ought to have been an indicator
> that there's an abstraction problem here.

Ok. Where such constraints should be instead? at the Hikey 970 DT
file?

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-17  6:55     ` Mauro Carvalho Chehab
@ 2020-11-17  9:51       ` Vinod Koul
  0 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-11-17  9:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, linuxarm, mauro.chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Krzysztof Kozlowski, Yu Chen, devel,
	devicetree, linux-kernel

On 17-11-20, 07:55, Mauro Carvalho Chehab wrote:
> Em Mon, 16 Nov 2020 09:31:06 -0600
> Rob Herring <robh@kernel.org> escreveu:
> 
> > On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote:
> > > The phy USB3 driver for Hisilicon 970 (hi3670) is ready
> > > for mainstream. Mode it from staging into the main driver's  
> > 
> > s/Mode/Move/
> > 
> > > phy/ directory.
> > > 
> > > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > > ---
> > >  .../bindings/phy/phy-hi3670-usb3.yaml         |  72 ++
> > >  MAINTAINERS                                   |   9 +-
> > >  drivers/phy/hisilicon/Kconfig                 |  10 +
> > >  drivers/phy/hisilicon/Makefile                |   1 +
> > >  drivers/phy/hisilicon/phy-hi3670-usb3.c       | 671 ++++++++++++++++++
> > >  drivers/staging/hikey9xx/Kconfig              |  11 -
> > >  drivers/staging/hikey9xx/Makefile             |   2 -
> > >  drivers/staging/hikey9xx/phy-hi3670-usb3.c    | 671 ------------------
> > >  drivers/staging/hikey9xx/phy-hi3670-usb3.yaml |  72 --  
> > 
> > I assume this is only a move? Use '-M' option.
> 
> This is a move, although I explicitly disabled -M on this series, as both
> the driver code and DT may still require some review, as those patches
> are for subsystems that I haven't made any relevant contributions
> so far.

I for one am appreciating the intent here, it helps to review the patch
coming in from staging

Thanks
-- 
~Vinod

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-17  8:08     ` Mauro Carvalho Chehab
@ 2020-11-17 14:25       ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2020-11-17 14:25 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, John Stultz, Manivannan Sadhasivam,
	Greg Kroah-Hartman, Liam Girdwood, Mayulong, YueHaibing, devel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1723 bytes --]

On Tue, Nov 17, 2020 at 09:08:22AM +0100, Mauro Carvalho Chehab wrote:
> Mark Brown <broonie@kernel.org> escreveu:

> > This probe code looks very different to other regulator drivers, this
> > alone should have been a warning that the driver needs some substantial
> > refactoring here.  As indicated information about what regulators are
> > present on devices and their properties should be in the driver not the
> > DT, the driver should just be able to register them unconditionally and
> > use of_match and regulators_node to allow the core to find any
> > constraints that are provided by the platform.

> The setup for MFD/regulator is different than almost all other
> regulator drivers currently upstreamed[1]. 

It really shouldn't be doing anything unusual.

> It means that, for the regulator driver to work, two drivers
> should be probed first: the SPMI bus controller driver
> (hisi-spmi-controller.c) and the SPMI bus client driver, which is
> at the MFD driver(hi6421-spmi-pmic.c).

> Only after having both probed, the regulator driver can be
> probed.

This is totally fine and very common for drivers in general, a
combination of probe deferral and fw_devlink exists to sort this stuff
out.

> Also, as all the communication between the PM chip
> and the SoC happens via a single serial bus, there's no
> sense on probing the regulators in parallel.

> That's mainly the reason why I opted to serialize the probe
> inside hi6421v600-regulator.c. 

I can't think of a regulator driver that doesn't have an entirly
serialized probe routine, that's not the issue.  The issue is that
almost nothing that the probe routine is doing is done by other
regulator drivers.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging
  2020-11-17  8:38     ` Mauro Carvalho Chehab
@ 2020-11-17 15:10       ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2020-11-17 15:10 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, John Stultz, Manivannan Sadhasivam,
	Greg Kroah-Hartman, Liam Girdwood, Mayulong, YueHaibing, devel,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4572 bytes --]

On Tue, Nov 17, 2020 at 09:38:30AM +0100, Mauro Carvalho Chehab wrote:
> Mark Brown <broonie@kernel.org> escreveu:

> > This also appears to be missing a DT binding document, binding
> > documentation is required for anything with DT support.

> The DT binding is documented on patch 3/8, together with MFD.

> As there's just one compatible for MFD and regulators altogether,
> I opted to have just one DT binding document for both.

I should've been copied on that patch then so the bindings can be
reviewed.

> > > +static DEFINE_MUTEX(enable_mutex);  

> > Drivers shouldn't be declaring global variables, if this is required it
> > should be allocated in driver data.

> I'll try to see a better place for this, but in this case, the
> mutex should be global anyway, as the access to the SPMI bus
> should be serialized.

Surely the bus should be dealing with basic I/O serialisation?

> > It looks like it would be less code overall to just implement a regmap
> > for the MFD, even if it were only used in this driver - almost
> > everything in here is just a carbon copy of standard helpers that the
> > core provides for regmap devices.  Doing it in the MFD would be more
> > idiomatic for everything though.

> I tried to use regmap for this driver while porting it from Linaro's
> OOT to upstream, bkut it turns that adding support for it is not trivial.

Could you expand on "not trivial" please?  What did you try and what
difficulties did you encounter?

> I suspect that, just like I2C has their own set of regmap functions
> (regmap_init_i2c, devm_regmap_init_i2c), if we want to properly support
> regmap, we need first to add a SPMI variant to it, as the locking
> should be bus-aware.

drivers/base/regmap/regmap-spmi.c has been there since 2013, or if for
some reason this device is doing something non-standard for the bus then
the reg_read() and reg_write() operations can be used.

> > > +	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);  

> > There is no way this stuff should be being parsed out of DT, we should
> > know the register map for the device and what regulators it has based
> > purely off knowing what device we have.  Baking the register map into
> > the ABI is bad practice, it prevents us from improving our support for
> > the hardware without going and updating people's DTs.

> Well, I can move the existing registers out of DT, but, as I don't
> have any datasheet for this device, it means that I can implement
> there only a subset of the available LDOs. So, from the 36 LDOs that
> this chip support, we only know the registers for 8 of them:

> 	ldo3, ldo4, ldo9, ldo15, ldo16, ldo17, ldo33 and ldo34.

People will be free to submit patches adding additional functionality to
the driver if they need it.

> > > +	/*
> > > +	 * Not all regulators work on idle mode
> > > +	 */
> > > +	ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask);

> > There's no conditional code to not register the mode operations if the
> > mode information is not available (and again this should be done based 
> > on knowing the properties of the device, this is unlikely to be system
> > dependent).

> This is the same case as before: as we don't have any datasheets,
> I only know what's there at the DT for just one device (Hikey 970).

> Again, we could hardcode those assuming Hikey 970 settings, but,
> if some other device using the same chip will ever be added, and
> they use some different configuration then we may face some
> backward-compatibility issues.

I can't follow the logic here, sorry.  If we have no idea how to
configure something how would offering operations to configure that
thing be useful?

> > > +	constraint->valid_modes_mask = REGULATOR_MODE_NORMAL;

> > This is absolutely not OK, a regulator driver should *not* be modifying
> > the constraints that the machine has set.  If it is safe to change modes
> > on a platform and the system integrator wants to do that then they will
> > set the constraints appropriately, there is no way the regulator driver
> > can tell what is appropriate on a given system.  The fact that the
> > driver is including machine.h at all ought to have been an indicator
> > that there's an abstraction problem here.

> Ok. Where such constraints should be instead? at the Hikey 970 DT
> file?

They should be configured whereever all the other constraints are
configured by the platform, if that is DT then they should also be
configured in DT.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy
  2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
  2020-11-16 15:31   ` Rob Herring
  2020-11-16 15:31   ` Rob Herring
@ 2020-11-30 10:30   ` Vinod Koul
  2 siblings, 0 replies; 21+ messages in thread
From: Vinod Koul @ 2020-11-30 10:30 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, linuxarm, mauro.chehab, John Stultz,
	Manivannan Sadhasivam, Alex Dewar, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Krzysztof Kozlowski, Yu Chen, devel,
	devicetree, linux-kernel

On 16-11-20, 13:59, Mauro Carvalho Chehab wrote:

> +#define CTRL7_USB2_REFCLKSEL_MASK	(3 << 3)
> +#define CTRL7_USB2_REFCLKSEL_ABB	(3 << 3)
> +#define CTRL7_USB2_REFCLKSEL_PAD	(2 << 3)

This should use GENMASK()
> +
> +#define CFG50_USB3_PHY_TEST_POWERDOWN	BIT(23)
> +
> +#define CFG54_USB31PHY_CR_ADDR_MASK	(0xFFFF)
> +#define CFG54_USB31PHY_CR_ADDR_SHIFT	(16)

We can skip this by using FIELD_GET/FIELD_SET macros and only define
register fields.

> +static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
> +{
> +	int ret;
> +
> +	if (direction)
> +		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +					 CFG54_USB31PHY_CR_WR_EN,
> +					 CFG54_USB31PHY_CR_WR_EN);
> +	else
> +		ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +					 CFG54_USB31PHY_CR_RD_EN,
> +					 CFG54_USB31PHY_CR_RD_EN);

how about:
        if direction
                reg = CFG54_USB31PHY_CR_WR_EN;
        else
                reg = CFG54_USB31PHY_CR_RD_EN;

        regmap_update_bits(usb31misc, USB_MISC_CFG54, reg, reg);
 
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = hi3670_phy_cr_clk(usb31misc);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(usb31misc, USB_MISC_CFG54,
> +				 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0);
> +
> +	return ret;

        return regmap_update_bits()

> +static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
> +{
> +	u32 reg;
> +	int retry = 100000;
> +	int ret;
> +
> +	while (retry-- > 0) {
> +		ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> +		if (ret)
> +			return ret;
> +		if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
> +			return 0;
> +
> +		ret = hi3670_phy_cr_clk(usb31misc);
> +		if (ret)
> +			return ret;

No delay in between reads..? maybe add a small delay and reduce the
retries?

> +static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
> +{
> +	u32 reg;
> +	int ret;
> +
> +	ret = regmap_read(usb31misc, USB_MISC_CFG54, &reg);
> +	if (ret)
> +		return ret;
> +
> +	reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT);
> +	reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT);
> +	ret = regmap_write(usb31misc, USB_MISC_CFG54, reg);

regmap_update_bits() ?

> +static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv)
> +{
> +	u32 reg;
> +
> +	if (!priv->sctrl) {
> +		dev_err(priv->dev, "priv->sctrl is null!\n");
> +		return 1;
> +	}
> +
> +	if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, &reg)) {
> +		dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
> +		return 1;

Not a -ve error code?
-- 
~Vinod

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2020-11-30 10:31 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-16 12:59 [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Mauro Carvalho Chehab
2020-11-16 12:59 ` [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy Mauro Carvalho Chehab
2020-11-16 15:31   ` Rob Herring
2020-11-17  6:55     ` Mauro Carvalho Chehab
2020-11-17  9:51       ` Vinod Koul
2020-11-16 15:31   ` Rob Herring
2020-11-30 10:30   ` Vinod Koul
2020-11-16 12:59 ` [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging Mauro Carvalho Chehab
2020-11-16 15:32   ` Rob Herring
2020-11-16 12:59 ` [PATCH 3/8] mfd: " Mauro Carvalho Chehab
2020-11-16 15:32   ` Rob Herring
2020-11-16 12:59 ` [PATCH 4/8] regulator: hi6421v600-regulator: move it " Mauro Carvalho Chehab
2020-11-16 18:38   ` Mark Brown
2020-11-17  8:08     ` Mauro Carvalho Chehab
2020-11-17 14:25       ` Mark Brown
2020-11-17  8:38     ` Mauro Carvalho Chehab
2020-11-17 15:10       ` Mark Brown
2020-11-16 12:59 ` [PATCH 5/8] arm64: dts: hisilicon: hi3670.dtsi: add I2C settings Mauro Carvalho Chehab
2020-11-16 12:59 ` [PATCH 6/8] arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings Mauro Carvalho Chehab
2020-11-16 12:59 ` [PATCH 7/8] dts: hisilicon: add support for USB3 on Hikey 970 Mauro Carvalho Chehab
2020-11-16 12:59 ` [PATCH 8/8] dts: hisilicon: add support for the PMIC found " Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).