linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
@ 2020-08-11 15:41 Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 01/33] spmi: get rid of a warning when built with W=1 Mauro Carvalho Chehab
                   ` (34 more replies)
  0 siblings, 35 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, linux-arm-msm,
	Liam Girdwood, linux-arm-kernel, Rob Herring, David S. Miller,
	Mark Brown, Rob Herring, Wei Xu, Stephen Boyd, Lee Jones,
	devicetree, Mayulong, linux-kernel

The Hikey 970 board uses a different PMIC than the one found on Hikey 960.

This PMIC uses a SPMI board.

This patch series backport the OOT drivers from the Linaro's official
tree for this board:

	https://github.com/96boards-hikey/linux/tree/hikey970-v4.9
	
Porting them to upstream, cleaning up coding style issues, solving
driver probing order and adding DT documentation.

I opted to not fold all patches into a single one, in order to:

- Preserve the authorship of the original authors;
- Keep a history of changes.

As this could be harder for people to review, I'll be replying to patch 00/32
with all patches folded. This should help reviewers to see the current
code after the entire series is applied.

Mauro Carvalho Chehab (32):
  spmi: get rid of a warning when built with W=1
  spmi: hisi-spmi-controller: coding style fixup
  mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC
  regulator: hisi_regulator_spmi: port it to upstream
  mfd: hisi_pmic_spmi: deal with non-static functions
  mfd: hisi_pmic_spmi: get rid of the static vars
  spmi: hisi-spmi-controller: fix it to probe successfully
  spmi: hisi-spmi-controller: fix a typo
  spmi: hisi-spmi-controller: adjust whitespaces at defines
  spmi: hisi-spmi-controller: use le32 macros where needed
  spmi: hisi-spmi-controller: add debug when values are read/write
  mfd, regulator: coding style fixups at the HiSilicon SPMI PMIC code
  spmi: add hisi-spmi-controller to the building system
  mfd: Kconfig: fix a typo
  spmi: hisi-spmi-controller: fix the dev_foo() logic
  mfd: pmic: add drivers for hi6421v600
  mfd: hi6421-spmi-pmic: get rid of unused OF properties
  spmi: hi6421-spmi-pmic: cleanup OF properties
  regulator: hi6421v600-regulator: cleanup struct hisi_regulator
  regulator: hi6421v600-regulator: cleanup debug messages
  regulator: hi6421v600-regulator: use shorter names for OF properties
  regulator: hi6421v600-regulator: better handle modes
  regulator, mfd: change namespace for HiSilicon SPMI PMIC drivers
  regulator: hi6421v600-regulator:  convert to use get/set voltage_sel
  regulator: hi6421v600-regulator: don't use usleep_range for
    off_on_delay
  regulator: hi6421v600-regulator: add a driver-specific debug macro
  regulator: hi6421v600-regulator: initialize ramp_delay
  regulator: hi6421v600-regulator: cleanup DT settings
  mfd, spmi, regulator: fix some coding style issues at HiSilicon SPMI
    PMIC
  dt: document HiSilicon SPMI controller and mfd/regulator properties
  dt: hisilicon: add support for the PMIC found on Hikey 970
  MAINTAINERS: add an entry for HiSilicon 6421v600 drivers

Mayulong (1):
  spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC

 .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 175 +++++++
 .../spmi/hisilicon,hisi-spmi-controller.yaml  |  54 ++
 MAINTAINERS                                   |   8 +
 .../boot/dts/hisilicon/hi3670-hikey970.dts    |  16 +-
 .../boot/dts/hisilicon/hikey970-pmic.dtsi     | 200 +++++++
 drivers/mfd/Kconfig                           |  17 +-
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/hi6421-spmi-pmic.c                | 399 ++++++++++++++
 drivers/regulator/Kconfig                     |   8 +
 drivers/regulator/Makefile                    |   1 +
 drivers/regulator/hi6421v600-regulator.c      | 493 ++++++++++++++++++
 drivers/spmi/Kconfig                          |   9 +
 drivers/spmi/Makefile                         |   2 +
 drivers/spmi/hisi-spmi-controller.c           | 384 ++++++++++++++
 drivers/spmi/spmi.c                           |  10 +-
 include/linux/mfd/hi6421-spmi-pmic.h          |  67 +++
 16 files changed, 1826 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.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/regulator/hi6421v600-regulator.c
 create mode 100644 drivers/spmi/hisi-spmi-controller.c
 create mode 100644 include/linux/mfd/hi6421-spmi-pmic.h

-- 
2.26.2



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

* [PATCH 01/33] spmi: get rid of a warning when built with W=1
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC Mauro Carvalho Chehab
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	linux-kernel, linux-arm-msm

The SPMI core complaing with this warning when built with W=1:

	drivers/spmi/spmi.c: In function ‘spmi_controller_remove’:
	drivers/spmi/spmi.c:548:6: warning: variable ‘dummy’ set but not used [-Wunused-but-set-variable]
	  548 |  int dummy;
	      |      ^~~~~

As the dummy var isn't needed, remove it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/spmi.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index c16b60f645a4..fd3ff6079b15 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -545,13 +545,10 @@ static int spmi_ctrl_remove_device(struct device *dev, void *data)
  */
 void spmi_controller_remove(struct spmi_controller *ctrl)
 {
-	int dummy;
-
 	if (!ctrl)
 		return;
 
-	dummy = device_for_each_child(&ctrl->dev, NULL,
-				      spmi_ctrl_remove_device);
+	device_for_each_child(&ctrl->dev, NULL, spmi_ctrl_remove_device);
 	device_del(&ctrl->dev);
 }
 EXPORT_SYMBOL_GPL(spmi_controller_remove);
-- 
2.26.2


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

* [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 01/33] spmi: get rid of a warning when built with W=1 Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:58   ` Mark Brown
  2020-08-11 15:41 ` [PATCH 03/33] spmi: hisi-spmi-controller: coding style fixup Mauro Carvalho Chehab
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mayulong, Mauro Carvalho Chehab,
	Lee Jones, Liam Girdwood, Mark Brown, Stephen Boyd, linux-kernel,
	linux-arm-msm

From: Mayulong <mayulong1@huawei.com>

Add the SPMI controller code and the MFD/regulator drivers needed
to support the PMIC used at the Hikey970 board.

[mchehab+huawei@kernel.org: keep just the sources, removing Kbuild changes]

Signed-off-by: Mayulong <mayulong1@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hisi_pmic_spmi.c            | 759 ++++++++++++++++++++++++
 drivers/regulator/hisi_regulator_spmi.c | 741 +++++++++++++++++++++++
 drivers/spmi/hisi-spmi-controller.c     | 390 ++++++++++++
 include/linux/mfd/hisi_pmic.h           | 165 ++++++
 4 files changed, 2055 insertions(+)
 create mode 100644 drivers/mfd/hisi_pmic_spmi.c
 create mode 100644 drivers/regulator/hisi_regulator_spmi.c
 create mode 100644 drivers/spmi/hisi-spmi-controller.c
 create mode 100644 include/linux/mfd/hisi_pmic.h

diff --git a/drivers/mfd/hisi_pmic_spmi.c b/drivers/mfd/hisi_pmic_spmi.c
new file mode 100644
index 000000000000..6bb0bc4b203b
--- /dev/null
+++ b/drivers/mfd/hisi_pmic_spmi.c
@@ -0,0 +1,759 @@
+/*
+ * 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/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/mfd/hisi_pmic.h>
+#include <linux/irq.h>
+#include <linux/spmi.h>
+#ifndef NO_IRQ
+#define NO_IRQ       0
+#endif
+
+/* 8-bit register offset in PMIC */
+#define HISI_MASK_STATE			0xff
+
+#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_NR_IRQ			25*/
+#define HISI_MASK_FIELD		0xFF
+#define HISI_BITS			8
+#define PMIC_FPGA_FLAG          1
+
+/*define the first group interrupt register number*/
+#define HISI_PMIC_FIRST_GROUP_INT_NUM        2
+
+static struct bit_info g_pmic_vbus = {0};
+#ifndef BIT
+#define BIT(x)		(0x1U << (x))
+#endif
+
+static struct hisi_pmic *g_pmic;
+static unsigned int g_extinterrupt_flag  = 0;
+static struct of_device_id of_hisi_pmic_match_tbl[] = {
+	{
+		.compatible = "hisilicon-hisi-pmic-spmi",
+	},
+	{ /* end */ }
+};
+
+/*
+ * 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.
+ */
+u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
+{
+	u32 ret;
+	u8 read_value = 0;
+	struct spmi_device *pdev;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return 0;
+	}
+
+	pdev = to_spmi_device(g_pmic->dev);
+	if (NULL == pdev) {
+		pr_err("%s:pdev get failed!\n", __func__);
+		return 0;
+	}
+
+	ret = spmi_ext_register_readl(pdev, reg, (unsigned char*)&read_value, 1);/*lint !e734 !e732 */
+	if (ret) {
+		pr_err("%s:spmi_ext_register_readl failed!\n", __func__);
+		return ret;
+	}
+	return (u32)read_value;
+}
+EXPORT_SYMBOL(hisi_pmic_read);
+
+void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
+{
+	u32 ret;
+	struct spmi_device *pdev;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return;
+	}
+
+	pdev = to_spmi_device(g_pmic->dev);
+	if (NULL == pdev) {
+		pr_err("%s:pdev get failed!\n", __func__);
+		return;
+	}
+
+	ret = spmi_ext_register_writel(pdev, reg, (unsigned char*)&val, 1);/*lint !e734 !e732 */
+	if (ret) {
+		pr_err("%s:spmi_ext_register_writel failed!\n", __func__);
+		return ;
+	}
+}
+EXPORT_SYMBOL(hisi_pmic_write);
+
+#ifdef CONFIG_HISI_DIEID
+u32 hisi_pmic_read_sub_pmu(u8 sid, int reg)
+{
+	u32 ret;
+	u8 read_value = 0;
+	struct spmi_device *pdev;
+
+	if(strstr(saved_command_line, "androidboot.swtype=factory"))
+	{
+		if (NULL == g_pmic) {
+			pr_err(" g_pmic  is NULL\n");
+			return -1;/*lint !e570 */
+		}
+
+		pdev = to_spmi_device(g_pmic->dev);
+		if (NULL == pdev) {
+			pr_err("%s:pdev get failed!\n", __func__);
+			return -1;/*lint !e570 */
+		}
+
+		ret = spmi_ext_register_readl(pdev->ctrl, sid, reg, (unsigned char*)&read_value, 1);/*lint !e734 !e732 */
+		if (ret) {
+			pr_err("%s:spmi_ext_register_readl failed!\n", __func__);
+			return ret;
+		}
+		return (u32)read_value;
+	}
+	return  0;
+}
+EXPORT_SYMBOL(hisi_pmic_read_sub_pmu);
+
+void hisi_pmic_write_sub_pmu(u8 sid, int reg, u32 val)
+{
+	u32 ret;
+	struct spmi_device *pdev;
+	if(strstr(saved_command_line, "androidboot.swtype=factory"))
+	{
+		if (NULL == g_pmic) {
+			pr_err(" g_pmic  is NULL\n");
+			return;
+		}
+
+		pdev = to_spmi_device(g_pmic->dev);
+		if (NULL == pdev) {
+			pr_err("%s:pdev get failed!\n", __func__);
+			return;
+		}
+
+		ret = spmi_ext_register_writel(pdev->ctrl, sid, reg, (unsigned char*)&val, 1);/*lint !e734 !e732 */
+		if (ret) {
+			pr_err("%s:spmi_ext_register_writel failed!\n", __func__);
+			return ;
+		}
+	}
+
+	return ;
+}
+EXPORT_SYMBOL(hisi_pmic_write_sub_pmu);
+#endif
+
+void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg,
+		     u32 mask, u32 bits)
+{
+	u32 data;
+	unsigned long flags;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return;
+	}
+
+	spin_lock_irqsave(&g_pmic->lock, flags);
+	data = hisi_pmic_read(pmic, reg) & ~mask;
+	data |= mask & bits;
+	hisi_pmic_write(pmic, reg, data);
+	spin_unlock_irqrestore(&g_pmic->lock, flags);
+}
+EXPORT_SYMBOL(hisi_pmic_rmw);
+
+unsigned int hisi_pmic_reg_read(int addr)
+{
+	return (unsigned int)hisi_pmic_read(g_pmic, addr);
+}
+EXPORT_SYMBOL(hisi_pmic_reg_read);
+
+void hisi_pmic_reg_write(int addr, int val)
+{
+	hisi_pmic_write(g_pmic, addr, val);
+}
+EXPORT_SYMBOL(hisi_pmic_reg_write);
+
+void hisi_pmic_reg_write_lock(int addr, int val)
+{
+	unsigned long flags;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return;
+	}
+
+	spin_lock_irqsave(&g_pmic->lock, flags);
+	hisi_pmic_write(g_pmic, g_pmic->normal_lock.addr, g_pmic->normal_lock.val);
+	hisi_pmic_write(g_pmic, g_pmic->debug_lock.addr, g_pmic->debug_lock.val);
+	hisi_pmic_write(g_pmic, addr, val);
+	hisi_pmic_write(g_pmic, g_pmic->normal_lock.addr, 0);
+	hisi_pmic_write(g_pmic, g_pmic->debug_lock.addr, 0);
+	spin_unlock_irqrestore(&g_pmic->lock, flags);
+}
+
+int hisi_pmic_array_read(int addr, char *buff, unsigned int len)
+{
+	unsigned int i;
+
+	if ((len > 32) || (NULL == buff)) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Here is a bug in the pmu die.
+	 * the coul driver will read 4 bytes,
+	 * but the ssi bus only read 1 byte, and the pmu die
+	 * will make sampling 1/10669us about vol cur,so the driver
+	 * read the data is not the same sampling
+	 */
+	for (i = 0; i < len; i++)
+	{
+		*(buff + i) = hisi_pmic_reg_read(addr+i);
+	}
+
+	return 0;
+}
+
+int hisi_pmic_array_write(int addr, char *buff, unsigned int len)
+{
+    unsigned int i;
+
+	if ((len > 32) || (NULL == buff)) {
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i++)
+	{
+		hisi_pmic_reg_write(addr+i, *(buff + i));
+	}
+
+	return 0;
+}
+
+static irqreturn_t hisi_irq_handler(int irq, void *data)
+{
+	struct hisi_pmic *pmic = (struct hisi_pmic *)data;
+	unsigned long pending;
+	int i, offset;
+
+	for (i = 0; i < pmic->irqarray; i++) {
+		pending = hisi_pmic_reg_read((i + pmic->irq_addr.start_addr));
+		pending &= HISI_MASK_FIELD;
+		if (pending != 0) {
+			pr_info("pending[%d]=0x%lx\n\r", i, pending);
+		}
+
+		hisi_pmic_reg_write((i + pmic->irq_addr.start_addr), pending);
+
+		/*solve powerkey order*/
+		if ((HISI_IRQ_KEY_NUM == i) && ((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]);/*lint !e679 */
+		}
+	}
+
+	/*Handle the second group irq if analysis the second group irq from dtsi*/
+	if (1 == g_extinterrupt_flag){
+		for (i = 0; i < pmic->irqarray1; i++) {
+			pending = hisi_pmic_reg_read((i + pmic->irq_addr1.start_addr));
+			pending &= HISI_MASK_FIELD;
+			if (pending != 0) {
+				pr_info("pending[%d]=0x%lx\n\r", i, pending);
+			}
+
+			hisi_pmic_reg_write((i + pmic->irq_addr1.start_addr), pending);
+
+			if (pending) {
+				for_each_set_bit(offset, &pending, HISI_BITS)
+					generic_handle_irq(pmic->irqs[offset + (i+HISI_PMIC_FIRST_GROUP_INT_NUM) * HISI_BITS]);/*lint !e679 */
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void hisi_irq_mask(struct irq_data *d)
+{
+	struct hisi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	u32 data, offset;
+	unsigned long flags;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return;
+	}
+
+	offset = (irqd_to_hwirq(d) >> 3);
+	if (1==g_extinterrupt_flag){
+		if ( offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
+			offset += pmic->irq_mask_addr.start_addr;
+		else/*Change addr when irq num larger than 16 because interrupt addr is nonsequence*/
+			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
+	}else{
+		offset += pmic->irq_mask_addr.start_addr;
+	}
+	spin_lock_irqsave(&g_pmic->lock, flags);
+	data = hisi_pmic_reg_read(offset);
+	data |= (1 << (irqd_to_hwirq(d) & 0x07));
+	hisi_pmic_reg_write(offset, data);
+	spin_unlock_irqrestore(&g_pmic->lock, flags);
+}
+
+static void hisi_irq_unmask(struct irq_data *d)
+{
+	struct hisi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	u32 data, offset;
+	unsigned long flags;
+
+	if (NULL == g_pmic) {
+		pr_err(" g_pmic  is NULL\n");
+		return;
+	}
+
+	offset = (irqd_to_hwirq(d) >> 3);
+	if (1==g_extinterrupt_flag){
+		if ( offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
+			offset += pmic->irq_mask_addr.start_addr;
+		else
+			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
+	}else{
+		offset += pmic->irq_mask_addr.start_addr;
+	}
+	spin_lock_irqsave(&g_pmic->lock, flags);
+	data = hisi_pmic_reg_read(offset);
+	data &= ~(1 << (irqd_to_hwirq(d) & 0x07)); /*lint !e502 */
+	hisi_pmic_reg_write(offset, data);
+	spin_unlock_irqrestore(&g_pmic->lock, flags);
+}
+
+static struct irq_chip hisi_pmu_irqchip = {
+	.name		= "hisi-irq",
+	.irq_mask	= hisi_irq_mask,
+	.irq_unmask	= hisi_irq_unmask,
+	.irq_disable	= hisi_irq_mask,
+	.irq_enable	= hisi_irq_unmask,
+};
+
+static int hisi_irq_map(struct irq_domain *d, unsigned int virq,
+			  irq_hw_number_t hw)
+{
+	struct hisi_pmic *pmic = d->host_data;
+
+	irq_set_chip_and_handler_name(virq, &hisi_pmu_irqchip,
+				      handle_simple_irq, "hisi");
+	irq_set_chip_data(virq, pmic);
+	irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+	return 0;
+}
+
+static struct irq_domain_ops hisi_domain_ops = {
+	.map	= hisi_irq_map,
+	.xlate	= irq_domain_xlate_twocell,
+};
+
+/*lint -e570 -e64*/
+static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *pmic)
+{
+	int ret = 0;
+
+	/*get pmic irq num*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num",
+						&(pmic->irqnum), 1);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-num property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*get pmic irq array number*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array",
+						&(pmic->irqarray), 1);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-array property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr",
+						(int *)&pmic->irq_mask_addr, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-mask-addr property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ0_ADDR*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr",
+						(int *)&pmic->irq_addr, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-addr property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-vbus",
+						(u32 *)&g_pmic_vbus, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-vbus property\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*pmic lock*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-lock",
+						(int *)&pmic->normal_lock, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-lock property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*pmic debug lock*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-debug-lock",
+						(int *)&pmic->debug_lock, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-debug-lock property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	return ret;
+}/*lint -restore*/
+
+
+/*lint -e570 -e64*/
+static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *pmic)
+{
+	int ret = 0;
+
+	/*get pmic irq num*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num1",
+						&(pmic->irqnum1), 1);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-num1 property set\n");
+		ret = -ENODEV;
+		pmic->irqnum1 = 0;
+		return ret;
+	}
+
+	/*get pmic irq array number*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array1",
+						&(pmic->irqarray1), 1);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-array1 property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr1",
+						(int *)&pmic->irq_mask_addr1, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-mask-addr1 property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ0_ADDR*/
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr1",
+						(int *)&pmic->irq_addr1, 2);
+	if (ret) {
+		pr_err("no hisilicon,hisi-pmic-irq-addr1 property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	g_extinterrupt_flag = 1;
+	return ret;
+}/*lint -restore*/
+
+int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list)
+{
+	if ( NULL == g_pmic ) {
+		pr_err("[%s]g_pmic is NULL\n", __func__);
+		return -1;
+	}
+
+	if (pmic_irq_list > (unsigned int)g_pmic->irqnum) {
+		pr_err("[%s]input pmic irq number is error.\n", __func__);
+		return -1;
+	}
+	pr_info("%s:g_pmic->irqs[%d]=%d\n", __func__, pmic_irq_list, g_pmic->irqs[pmic_irq_list]);
+	return (int)g_pmic->irqs[pmic_irq_list];
+}
+EXPORT_SYMBOL(hisi_get_pmic_irq_byname);
+
+int hisi_pmic_get_vbus_status(void)
+{
+	if (0 == g_pmic_vbus.addr)
+		return -1;
+
+	if (hisi_pmic_reg_read(g_pmic_vbus.addr) & BIT(g_pmic_vbus.bit))
+		return 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(hisi_pmic_get_vbus_status);
+
+static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
+{
+	int i;
+	for (i = 0 ; i < pmic->irq_mask_addr.array; i++) {
+		hisi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i, HISI_MASK_STATE);
+	}
+
+	for (i = 0 ; i < pmic->irq_addr.array; i++) {
+		unsigned int pending = hisi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
+		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n", pmic->irq_addr.start_addr + i, pending);
+		hisi_pmic_write(pmic, pmic->irq_addr.start_addr + i, HISI_MASK_STATE);
+	}
+
+}
+
+static void hisi_pmic_irq1_prc(struct hisi_pmic *pmic)
+{
+	int i;
+	if(1 == g_extinterrupt_flag){
+		for (i = 0 ; i < pmic->irq_mask_addr1.array; i++) {
+			hisi_pmic_write(pmic, pmic->irq_mask_addr1.start_addr + i, HISI_MASK_STATE);
+		}
+
+		for (i = 0 ; i < pmic->irq_addr1.array; i++) {
+			unsigned int pending1 = hisi_pmic_read(pmic, pmic->irq_addr1.start_addr + i);
+			pr_debug("PMU IRQ address1 value:irq[0x%x] = 0x%x\n", pmic->irq_addr1.start_addr + i, pending1);
+			hisi_pmic_write(pmic, pmic->irq_addr1.start_addr + i, HISI_MASK_STATE);
+		}
+	}
+}
+
+static int hisi_pmic_probe(struct spmi_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct hisi_pmic *pmic = NULL;
+	enum of_gpio_flags flags;
+	int ret = 0;
+	int i;
+	unsigned int fpga_flag = 0;
+	unsigned int virq;
+
+	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic) {
+		dev_err(dev, "cannot allocate hisi_pmic device info\n");
+		return -ENOMEM;
+	}
+
+	/*TODO: get pmic dts info*/
+	ret = get_pmic_device_tree_data(np, pmic);
+	if (ret) {
+		dev_err(&pdev->dev, "Error reading hisi pmic dts \n");
+		return ret;
+	}
+
+	/*get pmic dts the second group irq*/
+	ret = get_pmic_device_tree_data1(np, pmic);
+	if (ret) {
+		dev_err(&pdev->dev, "the platform don't support ext-interrupt.\n");
+	}
+
+	/* TODO: get and enable clk request */
+	spin_lock_init(&pmic->lock);
+
+	pmic->dev = dev;
+	g_pmic = pmic;
+	ret = of_property_read_u32_array(np, "hisilicon,pmic_fpga_flag", &fpga_flag, 1);
+	if (ret) {
+		pr_err("no hisilicon,pmic_fpga_flag property set\n");
+	}
+	if (PMIC_FPGA_FLAG == fpga_flag) {
+		goto after_irq_register;
+	}
+
+	pmic->gpio = of_get_gpio_flags(np, 0, &flags);
+	if (pmic->gpio < 0)
+		return pmic->gpio;
+
+	if (!gpio_is_valid(pmic->gpio))
+		return -EINVAL;
+
+	ret = gpio_request_one(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);
+
+	/* mask && clear IRQ status */
+	hisi_pmic_irq_prc(pmic);
+	/*clear && mask the new adding irq*/
+	hisi_pmic_irq1_prc(pmic);
+
+	pmic->irqnum += pmic->irqnum1;
+
+	pmic->irqs = (unsigned int *)devm_kmalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
+	if (!pmic->irqs) {
+		pr_err("%s:Failed to alloc memory for pmic irq number!\n", __func__);
+		goto irq_malloc;
+	}
+	memset(pmic->irqs, 0, pmic->irqnum);
+
+	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
+					     &hisi_domain_ops, pmic);
+	if (!pmic->domain) {
+		dev_err(dev, "failed irq domain add simple!\n");
+		ret = -ENODEV;
+		goto irq_domain;
+	}
+
+	for (i = 0; i < pmic->irqnum; i++) {
+		virq = irq_create_mapping(pmic->domain, i);
+		if (virq == NO_IRQ) {
+			pr_debug("Failed mapping hwirq\n");
+			ret = -ENOSPC;
+			goto irq_create_mapping;
+		}
+		pmic->irqs[i] = virq;
+		pr_info("[%s]. pmic->irqs[%d] = %d\n", __func__, i, pmic->irqs[i]);
+	}
+
+	ret = request_threaded_irq(pmic->irq, hisi_irq_handler, NULL,
+				IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+				   "pmic", pmic);
+	if (ret < 0) {
+		dev_err(dev, "could not claim pmic %d\n", ret);
+		ret = -ENODEV;
+		goto request_theaded_irq;
+	}
+
+after_irq_register:
+	return 0;
+
+
+request_theaded_irq:
+irq_create_mapping:
+irq_domain:
+irq_malloc:
+	gpio_free(pmic->gpio);
+	g_pmic = NULL;
+	return ret;
+}
+
+static void hisi_pmic_remove(struct spmi_device *pdev)
+{
+
+	struct hisi_pmic *pmic = dev_get_drvdata(&pdev->dev);
+
+	free_irq(pmic->irq, pmic);
+	gpio_free(pmic->gpio);
+	devm_kfree(&pdev->dev, pmic);
+
+}
+static int hisi_pmic_suspend(struct device *dev, pm_message_t state)
+{
+	struct hisi_pmic *pmic = dev_get_drvdata(dev);
+
+	if (NULL == pmic) {
+		pr_err("%s:pmic is NULL\n", __func__);
+		return -ENOMEM;
+	}
+
+	pr_info("%s:+\n", __func__);
+	pr_info("%s:-\n", __func__);
+
+	return 0;
+}/*lint !e715 */
+
+static int hisi_pmic_resume(struct device *dev)
+{
+	struct hisi_pmic *pmic = dev_get_drvdata(dev);
+
+	if (NULL == pmic) {
+		pr_err("%s:pmic is NULL\n", __func__);
+		return -ENOMEM;
+	}
+
+	pr_info("%s:+\n", __func__);
+	pr_info("%s:-\n", __func__);
+
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(spmi, pmic_spmi_id);
+static struct spmi_driver hisi_pmic_driver = {
+	.driver = {
+		.name	= "hisi_pmic",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_hisi_pmic_match_tbl,
+		.suspend = hisi_pmic_suspend,
+		.resume = hisi_pmic_resume,
+	},
+	.probe	= hisi_pmic_probe,
+	.remove	= hisi_pmic_remove,
+};
+
+static int __init hisi_pmic_init(void)
+{
+	return spmi_driver_register(&hisi_pmic_driver);
+}
+
+static void __exit hisi_pmic_exit(void)
+{
+	spmi_driver_unregister(&hisi_pmic_driver);
+}
+
+
+subsys_initcall_sync(hisi_pmic_init);
+module_exit(hisi_pmic_exit);
+
+MODULE_DESCRIPTION("PMIC driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/regulator/hisi_regulator_spmi.c b/drivers/regulator/hisi_regulator_spmi.c
new file mode 100644
index 000000000000..941bfe32bf5b
--- /dev/null
+++ b/drivers/regulator/hisi_regulator_spmi.c
@@ -0,0 +1,741 @@
+/*
+ * 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/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/hisi_pmic.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#ifdef CONFIG_HISI_PMIC_DEBUG
+#include <linux/debugfs.h>
+#endif
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/spmi.h>
+
+#if 1
+#define BRAND_DEBUG(args...) pr_debug(args);
+#else
+#define BRAND_DEBUG(args...)
+#endif
+
+struct hisi_regulator_register_info {
+	u32 ctrl_reg;
+	u32 enable_mask;
+	u32 eco_mode_mask;
+	u32 vset_reg;
+	u32 vset_mask;
+};
+
+struct hisi_regulator {
+	const char *name;
+	struct hisi_regulator_register_info register_info;
+	struct timeval last_off_time;
+	u32 off_on_delay;
+	u32 eco_uA;
+	struct regulator_desc rdesc;
+	int (*dt_parse)(struct hisi_regulator *, struct spmi_device *);
+};
+
+static DEFINE_MUTEX(enable_mutex);
+struct timeval last_enabled;
+
+
+static inline struct hisi_pmic *rdev_to_pmic(struct regulator_dev *dev)
+{
+	/* regulator_dev parent to->
+	 * hisi regulator platform device_dev parent to->
+	 * hisi pmic platform device_dev
+	 */
+	return dev_get_drvdata(rdev_get_dev(dev)->parent->parent);
+}
+
+/* helper function to ensure when it returns it is at least 'delay_us'
+ * microseconds after 'since'.
+ */
+static void ensured_time_after(struct timeval since, u32 delay_us)
+{
+	struct timeval now;
+	u64 elapsed_ns64, delay_ns64;
+	u32 actual_us32;
+
+	delay_ns64 = delay_us * NSEC_PER_USEC;
+	do_gettimeofday(&now);
+	elapsed_ns64 = timeval_to_ns(&now) - timeval_to_ns(&since);
+	if (delay_ns64 > elapsed_ns64) {
+		actual_us32 = ((u32)(delay_ns64 - elapsed_ns64) /
+							NSEC_PER_USEC);
+		if (actual_us32 >= 1000) {
+			mdelay(actual_us32 / 1000); /*lint !e647 */
+			udelay(actual_us32 % 1000);
+		} else if (actual_us32 > 0) {
+			udelay(actual_us32);
+		}
+	}
+	return;
+}
+
+static int hisi_regulator_is_enabled(struct regulator_dev *dev)
+{
+	u32 reg_val;
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+
+	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
+	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n", __func__, sreg->register_info.ctrl_reg,\
+			(reg_val & sreg->register_info.enable_mask));
+
+	return ((reg_val & sreg->register_info.enable_mask) != 0);
+}
+
+static int hisi_regulator_enable(struct regulator_dev *dev)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+
+	/* keep a distance of off_on_delay from last time disabled */
+	ensured_time_after(sreg->last_off_time, sreg->off_on_delay);
+
+	BRAND_DEBUG("<[%s]: off_on_delay=%dus>\n", __func__, sreg->off_on_delay);
+
+	/* cannot enable more than one regulator at one time */
+	mutex_lock(&enable_mutex);
+	ensured_time_after(last_enabled, HISI_REGS_ENA_PROTECT_TIME);
+
+	/* set enable register */
+	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+				sreg->register_info.enable_mask,
+				sreg->register_info.enable_mask);
+	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n", __func__, sreg->register_info.ctrl_reg,\
+			sreg->register_info.enable_mask);
+
+	do_gettimeofday(&last_enabled);
+	mutex_unlock(&enable_mutex);
+
+	return 0;
+}
+
+static int hisi_regulator_disable(struct regulator_dev *dev)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+
+	/* set enable register to 0 */
+	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+				sreg->register_info.enable_mask, 0);
+
+	do_gettimeofday(&sreg->last_off_time);
+
+	return 0;
+}
+
+static int hisi_regulator_get_voltage(struct regulator_dev *dev)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	u32 reg_val, selector;
+
+	/* get voltage selector */
+	reg_val = hisi_pmic_read(pmic, sreg->register_info.vset_reg);
+	BRAND_DEBUG("<[%s]: vset_reg=0x%x>\n", __func__, sreg->register_info.vset_reg);
+
+	selector = (reg_val & sreg->register_info.vset_mask) >>
+				(ffs(sreg->register_info.vset_mask) - 1);
+
+	return sreg->rdesc.ops->list_voltage(dev, selector);
+}
+
+static int hisi_regulator_set_voltage(struct regulator_dev *dev,
+				int min_uV, int max_uV, unsigned *selector)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	u32 vsel;
+	int ret = 0;
+
+	for (vsel = 0; vsel < sreg->rdesc.n_voltages; vsel++) {
+		int uV = sreg->rdesc.volt_table[vsel];
+		/* Break at the first in-range value */
+		if (min_uV <= uV && uV <= max_uV)
+			break;
+	}
+
+	/* unlikely to happen. sanity test done by regulator core */
+	if (unlikely(vsel == sreg->rdesc.n_voltages))
+		return -EINVAL;
+
+	*selector = vsel;
+	/* set voltage selector */
+	hisi_pmic_rmw(pmic, sreg->register_info.vset_reg,
+		sreg->register_info.vset_mask,
+		vsel << (ffs(sreg->register_info.vset_mask) - 1));
+
+	BRAND_DEBUG("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n", __func__,\
+			sreg->register_info.vset_reg,\
+			sreg->register_info.vset_mask,\
+			vsel << (ffs(sreg->register_info.vset_mask) - 1)\
+			);
+
+	return ret;
+}
+
+static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	u32 reg_val;
+
+	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
+	BRAND_DEBUG("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n", __func__, reg_val,\
+			sreg->register_info.ctrl_reg,\
+			sreg->register_info.eco_mode_mask\
+		   );
+
+	if (reg_val & sreg->register_info.eco_mode_mask)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int hisi_regulator_set_mode(struct regulator_dev *dev,
+						unsigned int mode)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	u32 eco_mode;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		eco_mode = HISI_ECO_MODE_DISABLE;
+		break;
+	case REGULATOR_MODE_IDLE:
+		eco_mode = HISI_ECO_MODE_ENABLE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set mode */
+	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+		sreg->register_info.eco_mode_mask,
+		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
+
+	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n", __func__,\
+			sreg->register_info.ctrl_reg,\
+			sreg->register_info.eco_mode_mask,\
+			eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1)\
+		   );
+	return 0;
+}
+
+
+unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+
+	if ((load_uA == 0) || ((unsigned int)load_uA > sreg->eco_uA))
+		return REGULATOR_MODE_NORMAL;
+	else
+		return REGULATOR_MODE_IDLE;
+}
+
+static int hisi_dt_parse_common(struct hisi_regulator *sreg,
+					struct spmi_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct regulator_desc *rdesc = &sreg->rdesc;
+	unsigned int register_info[3] = {0};
+	int ret = 0;
+
+	/* parse .register_info.ctrl_reg */
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-ctrl",
+						register_info, 3);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-ctrl property set\n");
+		goto dt_parse_common_end;
+	}
+	sreg->register_info.ctrl_reg = register_info[0];
+	sreg->register_info.enable_mask = register_info[1];
+	sreg->register_info.eco_mode_mask = register_info[2];
+
+	/* parse .register_info.vset_reg */
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset",
+						register_info, 2);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-vset property set\n");
+		goto dt_parse_common_end;
+	}
+	sreg->register_info.vset_reg = register_info[0];
+	sreg->register_info.vset_mask = register_info[1];
+
+	/* parse .off-on-delay */
+	ret = of_property_read_u32(np, "hisilicon,hisi-off-on-delay-us",
+						&sreg->off_on_delay);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-off-on-delay-us property set\n");
+		goto dt_parse_common_end;
+	}
+
+	/* parse .enable_time */
+	ret = of_property_read_u32(np, "hisilicon,hisi-enable-time-us",
+				   &rdesc->enable_time);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-enable-time-us property set\n");
+		goto dt_parse_common_end;
+	}
+
+	/* parse .eco_uA */
+	ret = of_property_read_u32(np, "hisilicon,hisi-eco-microamp",
+				   &sreg->eco_uA);
+	if (ret) {
+		sreg->eco_uA = 0;
+		ret = 0;
+	}
+
+dt_parse_common_end:
+	return ret;
+}
+
+static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
+				struct spmi_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct regulator_desc *rdesc = &sreg->rdesc;
+	unsigned int *v_table;
+	int ret = 0;
+
+	/* parse .n_voltages, and .volt_table */
+	ret = of_property_read_u32(np, "hisilicon,hisi-n-voltages",
+				   &rdesc->n_voltages);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-n-voltages property set\n");
+		goto dt_parse_ldo_end;
+	}
+
+	/* alloc space for .volt_table */
+	v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
+								GFP_KERNEL);
+	if (unlikely(!v_table)) {
+		ret = -ENOMEM;
+		dev_err(dev, "no memory for .volt_table\n");
+		goto dt_parse_ldo_end;
+	}
+
+	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset-table",
+						v_table, rdesc->n_voltages);
+	if (ret) {
+		dev_err(dev, "no hisilicon,hisi-vset-table property set\n");
+		goto dt_parse_ldo_end1;
+	}
+	rdesc->volt_table = v_table;
+
+	/* parse hisi regulator's dt common part */
+	ret = hisi_dt_parse_common(sreg, pdev);
+	if (ret) {
+		dev_err(dev, "failure in hisi_dt_parse_common\n");
+		goto dt_parse_ldo_end1;
+	}
+
+	return ret;
+
+dt_parse_ldo_end1:
+dt_parse_ldo_end:
+	return ret;
+}
+
+static struct regulator_ops hisi_ldo_rops = {
+	.is_enabled = hisi_regulator_is_enabled,
+	.enable = hisi_regulator_enable,
+	.disable = hisi_regulator_disable,
+	.list_voltage = regulator_list_voltage_table,
+	.get_voltage = hisi_regulator_get_voltage,
+	.set_voltage = hisi_regulator_set_voltage,
+	.get_mode = hisi_regulator_get_mode,
+	.set_mode = hisi_regulator_set_mode,
+	.get_optimum_mode = hisi_regulator_get_optimum_mode,
+};
+
+static const struct hisi_regulator hisi_regulator_ldo = {
+	.rdesc = {
+	.ops = &hisi_ldo_rops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+		},
+	.dt_parse = hisi_dt_parse_ldo,
+};
+
+static struct of_device_id of_hisi_regulator_match_tbl[] = {
+	{
+		.compatible = "hisilicon-hisi-ldo",
+		.data = &hisi_regulator_ldo,
+	},
+	{ /* end */ }
+};
+
+#ifdef CONFIG_HISI_PMIC_DEBUG
+extern void get_current_regulator_dev(struct seq_file *s);
+extern void set_regulator_state(char *ldo_name, int value);
+extern void get_regulator_state(char *ldo_name);
+extern int set_regulator_voltage(char *ldo_name, unsigned int vol_value);
+
+u32 pmu_atoi(char *s)
+{
+	char *p = s;
+	char c;
+	u64 ret = 0;
+	if (s == NULL)
+		return 0;
+	while ((c = *p++) != '\0') {
+		if ('0' <= c && c <= '9') {
+			ret *= 10;
+			ret += (u64)((unsigned char)c - '0');
+			if (ret > U32_MAX)
+				return 0;
+		} else {
+			break;
+		}
+	}
+	return (u32)ret;
+}
+static int dbg_hisi_regulator_show(struct seq_file *s, void *data)
+{
+	seq_printf(s, "\n\r");
+	seq_printf(s, "%-13s %-15s %-15s %-15s %-15s\n\r",
+			"LDO_NAME", "ON/OFF", "Use_count", "Open_count", "Always_on");
+	seq_printf(s, "-----------------------------------------"
+			"-----------------------------------------------\n\r");
+	get_current_regulator_dev(s);
+	return 0;
+}
+
+static int dbg_hisi_regulator_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dbg_hisi_regulator_show, inode->i_private);
+}
+
+static const struct file_operations debug_regulator_state_fops = {
+	.open		= dbg_hisi_regulator_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int dbg_control_regulator_show(struct seq_file *s, void *data)
+{
+	printk("                                                                             \n\r \
+		---------------------------------------------------------------------------------\n\r \
+		|usage:                                                                         |\n\r \
+		|	S = state	R = read	V = voltage                                         |\n\r \
+		|	set ldo state and voltage                                                   |\n\r \
+		|	get ldo state and current voltage                                           |\n\r \
+		|example:                                                                       |\n\r \
+		|	echo S ldo16 0   > control_regulator	:disable ldo16                      |\n\r \
+		|	echo S ldo16 1   > control_regulator	:enable ldo16                       |\n\r \
+		|	echo R ldo16     > control_regulator	:get ldo16 state and voltage        |\n\r \
+		|	echo V ldo16 xxx > control_regulator	:set ldo16 voltage                  |\n\r \
+		---------------------------------------------------------------------------------\n\r");
+	return 0;
+}
+static ssize_t dbg_control_regulator_set_value(struct file *filp, const char __user *buffer,
+	size_t count, loff_t *ppos)
+{
+	char tmp[128] = {0};
+	char ptr[128] = {0};
+	char *vol = NULL;
+	char num = 0;
+	unsigned int i;
+	int next_flag = 1;
+
+	if (count >= 128) {
+		pr_info("error! buffer size big than internal buffer\n");
+		return -EFAULT;
+	}
+
+	if (copy_from_user(tmp, buffer, count)) {
+		pr_info("error!\n");
+		return -EFAULT;
+	}
+
+	if (tmp[0] == 'R' || tmp[0] == 'r') {
+		for (i = 2; i < (count - 1); i++) {
+			ptr[i - 2] = tmp[i];
+		}
+		ptr[i - 2] = '\0';
+		get_regulator_state(ptr);
+	} else if (tmp[0] == 'S' || tmp[0] == 's') {
+		for (i = 2; i < (count - 1); i++) {
+			if (tmp[i] == ' ') {
+				next_flag = 0;
+				ptr[i - 2] = '\0';
+				continue;
+			}
+			if (next_flag) {
+				ptr[i - 2] = tmp[i];
+			} else {
+				num = tmp[i] - 48;
+			}
+		}
+		set_regulator_state(ptr, num);
+	} else if (tmp[0] == 'V' || tmp[0] == 'v') {
+		for (i = 2; i < (count - 1); i++) {
+			if (tmp[i] == ' ') {
+				next_flag = 0;
+				ptr[i - 2] = '\0';
+				continue;
+			}
+			if (next_flag) {
+				ptr[i - 2] = tmp[i];
+			} else {
+				vol = &tmp[i];
+				break;
+			}
+		}
+		set_regulator_voltage(ptr, pmu_atoi(vol));
+	}
+
+	*ppos += count;
+
+	return count;
+}
+
+static int dbg_control_regulator_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return single_open(file, dbg_control_regulator_show, &inode->i_private);
+}
+
+static const struct file_operations set_control_regulator_fops = {
+	.open		= dbg_control_regulator_open,
+	.read		= seq_read,
+	.write		= dbg_control_regulator_set_value,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+#endif
+
+static int hisi_regulator_probe(struct spmi_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct hisi_regulator *sreg = NULL;
+	struct regulator_init_data *initdata;
+	struct regulator_config config = { };
+	const struct of_device_id *match;
+	struct regulation_constraints *constraint;
+	const char *supplyname = NULL;
+#ifdef CONFIG_HISI_PMIC_DEBUG
+	struct dentry *d;
+	static int debugfs_flag;
+#endif
+	unsigned int temp_modes;
+
+	const struct hisi_regulator *template = NULL;
+	int ret = 0;
+	/* to check which type of regulator this is */
+	match = of_match_device(of_hisi_regulator_match_tbl, &pdev->dev);
+	if (NULL == match) {
+		pr_err("get hisi regulator fail!\n\r");
+		return -EINVAL;
+	}
+
+	template = match->data;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0))
+	initdata = of_get_regulator_init_data(dev, np, NULL);
+#else
+	initdata = of_get_regulator_init_data(dev, np);
+#endif
+	if (NULL == initdata) {
+		pr_err("get regulator init data error !\n");
+		return -EINVAL;
+	}
+
+	/* hisi regulator supports two modes */
+	constraint = &initdata->constraints;
+
+	ret = of_property_read_u32_array(np, "hisilicon,valid-modes-mask",
+						&(constraint->valid_modes_mask), 1);
+	if (ret) {
+		pr_err("no hisilicon,valid-modes-mask property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+	ret = of_property_read_u32_array(np, "hisilicon,valid-idle-mask",
+						&temp_modes, 1);
+	if (ret) {
+		pr_err("no hisilicon,valid-modes-mask property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+	constraint->valid_ops_mask |= temp_modes;
+
+	sreg = kmemdup(template, sizeof(*sreg), GFP_KERNEL);
+	if (!sreg) {
+		pr_err("template kememdup is fail. \n");
+		return -ENOMEM;
+	}
+	sreg->name = initdata->constraints.name;
+	rdesc = &sreg->rdesc;
+	rdesc->name = sreg->name;
+	rdesc->min_uV = initdata->constraints.min_uV;
+	supplyname = of_get_property(np, "hisilicon,supply_name", NULL);
+	if (supplyname != NULL) {
+		initdata->supply_regulator = supplyname;
+	}
+
+	/* to parse device tree data for regulator specific */
+	ret = sreg->dt_parse(sreg, pdev);
+	if (ret) {
+		dev_err(dev, "device tree parameter parse error!\n");
+		goto hisi_probe_end;
+	}
+
+	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);
+		ret = PTR_ERR(rdev);
+		goto hisi_probe_end;
+	}
+
+	BRAND_DEBUG("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n", rdesc->name,\
+			constraint->valid_modes_mask, constraint->valid_ops_mask);
+
+	dev_set_drvdata(dev, rdev);
+#ifdef CONFIG_HISI_PMIC_DEBUG
+	if (debugfs_flag == 0) {
+		d = debugfs_create_dir("hisi_regulator_debugfs", NULL);
+		if (!d) {
+			dev_err(dev, "failed to create hisi regulator debugfs dir !\n");
+			ret = -ENOMEM;
+			goto hisi_probe_fail;
+		}
+		(void) debugfs_create_file("regulator_state", S_IRUSR,
+						d, NULL, &debug_regulator_state_fops);
+
+		(void) debugfs_create_file("control_regulator", S_IRUSR,
+						d, NULL, &set_control_regulator_fops);
+		debugfs_flag = 1;
+	}
+#endif
+
+#ifdef CONFIG_HISI_PMIC_DEBUG
+hisi_probe_fail:
+	if (ret)
+		regulator_unregister(rdev);
+#endif
+hisi_probe_end:
+	if (ret)
+		kfree(sreg);
+	return ret;
+}
+
+static void hisi_regulator_remove(struct spmi_device *pdev)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev);
+	struct hisi_regulator *sreg = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+
+	/* TODO: should i worry about that? devm_kzalloc */
+	if (sreg->rdesc.volt_table)
+		devm_kfree(&pdev->dev, (unsigned int *)sreg->rdesc.volt_table);
+
+	kfree(sreg);
+}
+static int hisi_regulator_suspend(struct device *dev, pm_message_t state)
+{
+	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
+
+	if (NULL == hisi_regulator) {
+		pr_err("%s:regulator is NULL\n", __func__);
+		return -ENOMEM;
+	}
+
+	pr_info("%s:+\n", __func__);
+	pr_info("%s:-\n", __func__);
+
+	return 0;
+}/*lint !e715 */
+
+static int hisi_regulator_resume(struct device *dev)
+{
+	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
+
+	if (NULL == hisi_regulator) {
+		pr_err("%s:regulator is NULL\n", __func__);
+		return -ENOMEM;
+	}
+
+	pr_info("%s:+\n", __func__);
+	pr_info("%s:-\n", __func__);
+
+	return 0;
+}
+
+static struct spmi_driver hisi_pmic_driver = {
+	.driver = {
+		.name	= "hisi_regulator",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_hisi_regulator_match_tbl,
+		.suspend = hisi_regulator_suspend,
+		.resume = hisi_regulator_resume,
+	},
+	.probe	= hisi_regulator_probe,
+	.remove	= hisi_regulator_remove,
+};
+
+static int __init hisi_regulator_init(void)
+{
+	return spmi_driver_register(&hisi_pmic_driver);
+}
+
+static void __exit hisi_regulator_exit(void)
+{
+	spmi_driver_unregister(&hisi_pmic_driver);
+}
+
+fs_initcall(hisi_regulator_init);
+module_exit(hisi_regulator_exit);
+
+MODULE_DESCRIPTION("Hisi regulator driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
new file mode 100644
index 000000000000..987526c8b49f
--- /dev/null
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -0,0 +1,390 @@
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/spmi.h>
+#include <linux/spmi.h>
+
+#define SPMI_CONTROLLER_NAME		"spmi_controller"
+
+/*
+ * SPMI register addr
+ */
+#define SPMI_CHANNEL_OFFSET					0x0300
+#define SPMI_SLAVE_OFFSET						0x20
+
+#define SPMI_APB_SPMI_CMD_BASE_ADDR				0x0100
+/*lint -e750 -esym(750,*)*/
+#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
+/*lint +e750 -esym(750,*)*/
+
+#define SPMI_PER_DATAREG_BYTE					4
+/*
+ * SPMI cmd register
+ */
+#define SPMI_APB_SPMI_CMD_EN						(1 << 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
+
+#define Tranverse32(X)                 ((((u32)(X) & 0xff000000) >> 24) | \
+							   (((u32)(X) & 0x00ff0000) >> 8) | \
+							   (((u32)(X) & 0x0000ff00) << 8) | \
+							   (((u32)(X) & 0x000000ff) << 24))
+
+/* Command Opcodes */
+/*lint -e749 -esym(749,*)*/
+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,
+};
+/*lint +e749 -esym(749,*)*/
+
+/*
+ * SPMI status register
+ */
+#define SPMI_APB_TRANS_DONE						(1 << 0)
+#define SPMI_APB_TRANS_FAIL						(1 << 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)
+
+#define SPMI_WRITEL( dev, reg, addr )	\
+	do { \
+		writel( ( reg ), ( addr ) ); \
+	} while (0)
+
+#define  SPMI_READL( dev, reg, addr )	\
+	do { \
+		reg = readl( addr ); \
+	} while (0)
+
+/*
+ * @base base address of the PMIC Arbiter core registers.
+ * @rdbase, @wrbase base address of the PMIC Arbiter read core registers.
+ *     For HW-v1 these are equal to base.
+ *     For HW-v2, the value is the same in eeraly probing, in order to read
+ *     PMIC_ARB_CORE registers, then chnls, and obsrvr are set to
+ *     PMIC_ARB_CORE_REGISTERS and PMIC_ARB_CORE_REGISTERS_OBS respectivly.
+ * @intr base address of the SPMI interrupt control registers
+ * @ppid_2_chnl_tbl lookup table f(SID, Periph-ID) -> channel num
+ *      entry is only valid if corresponding bit is set in valid_ppid_bitmap.
+ * @valid_ppid_bitmap bit is set only for valid ppids.
+ * @fmt_cmd formats a command to be set into PMIC_ARBq_CHNLn_CMD
+ * @chnl_ofst calculates offset of the base of a channel reg space
+ * @ee execution environment id
+ * @irq_acc0_init_val initial value of the interrupt accumulator at probe time.
+ *      Use for an HW workaround. On handling interrupts, the first accumulator
+ *      register will be compared against this value, and bits which are set at
+ *      boot will be ignored.
+ * @reserved_chnl entry of ppid_2_chnl_tbl that this driver should never touch.
+ *      value is positive channel number or negative to mark it unused.
+ */
+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 spmi_controller_dev *ctrl_dev,
+				  void __iomem *base, u8 sid, u16 addr)
+{
+	u32 status = 0;
+	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
+	u32 offset = SPMI_APB_SPMI_STATUS_BASE_ADDR + SPMI_CHANNEL_OFFSET * ctrl_dev->channel
+		+ SPMI_SLAVE_OFFSET * sid;
+
+	while (timeout--) {
+		SPMI_READL(ctrl_dev->dev, status, base + offset);/*lint !e732 */
+
+		if (status & SPMI_APB_TRANS_DONE) {
+			if (status & SPMI_APB_TRANS_FAIL) {
+				dev_err(ctrl_dev->dev,
+					"%s: transaction failed (0x%x)\n",
+					__func__, status);
+				return -EIO;
+			}
+			return 0;
+		}
+		udelay(1);/*lint !e778 !e774 !e747*/
+	}
+
+	dev_err(ctrl_dev->dev,
+		"%s: timeout, status 0x%x\n",
+		__func__, status);
+	return -ETIMEDOUT;/*lint !e438*/
+}/*lint !e715 !e529*/
+
+static int spmi_read_cmd(struct spmi_controller *ctrl,
+				u8 opc, u8 sid, u16 addr, u8 *buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	unsigned long flags;
+	u32 cmd, data;
+	int rc;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET*spmi_controller->channel;
+	u8 op_code, i;
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(spmi_controller->dev
+		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
+					, SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	/* Check the opcode */
+	if (SPMI_CMD_READ == opc)
+		op_code = SPMI_CMD_REG_READ;
+	else if (SPMI_CMD_EXT_READ == opc)
+		op_code = SPMI_CMD_EXT_REG_READ;
+	else if (SPMI_CMD_EXT_READL == opc)
+		op_code = SPMI_CMD_EXT_REG_READ_L;
+	else {
+		dev_err(spmi_controller->dev, "invalid read cmd 0x%x", opc);
+		return -EINVAL;
+	}
+
+	cmd = SPMI_APB_SPMI_CMD_EN |/*lint !e648 !e701 */								/* cmd_en */
+		 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |/*lint !e648 !e701 */			/* cmd_type */
+		 ((bc-1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |/*lint !e648 !e701 */		/* byte_cnt */
+		 ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |						/* slvid */
+		 ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);					/* slave_addr */
+
+	spin_lock_irqsave(&spmi_controller->lock, flags);/*lint !e550 */
+
+	SPMI_WRITEL(spmi_controller->dev, cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+
+	rc = spmi_controller_wait_for_done(spmi_controller, spmi_controller->base, sid, addr);
+	if (rc)
+		goto done;
+
+	i = 0;
+	do {
+		SPMI_READL(spmi_controller->dev, data, spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET*sid + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i*SPMI_PER_DATAREG_BYTE);/*lint !e732 */
+		data = Tranverse32(data);
+		if ((bc - i*SPMI_PER_DATAREG_BYTE ) >> 2) {/*lint !e702 */
+			memcpy(buf, &data, sizeof(data));
+			buf += sizeof(data);
+		} else {
+			memcpy(buf, &data, bc%SPMI_PER_DATAREG_BYTE);/*lint !e747 */
+			buf += (bc%SPMI_PER_DATAREG_BYTE);
+		}
+		i++;
+	} while (bc > i*SPMI_PER_DATAREG_BYTE);
+
+done:
+	spin_unlock_irqrestore(&spmi_controller->lock, flags);
+	if (rc)
+		dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
+							opc, sid, addr, bc + 1);
+	return rc;
+}/*lint !e550 !e529*/
+
+/*lint -e438 -esym(438,*)*/
+static int spmi_write_cmd(struct spmi_controller *ctrl,
+				u8 opc, u8 sid, u16 addr, const u8 *buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	unsigned long flags;
+	u32 cmd;
+	u32 data = 0;
+	int rc;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET*spmi_controller->channel;
+	u8 op_code, i;
+
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(spmi_controller->dev
+		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
+					, SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	/* Check the opcode */
+	if (SPMI_CMD_WRITE == opc)
+		op_code = SPMI_CMD_REG_WRITE;
+	else if (SPMI_CMD_EXT_WRITE == opc)
+		op_code = SPMI_CMD_EXT_REG_WRITE;
+	else if (SPMI_CMD_EXT_WRITEL == opc)
+		op_code = SPMI_CMD_EXT_REG_WRITE_L;
+	else {
+		dev_err(spmi_controller->dev, "invalid write cmd 0x%x", opc);
+		return -EINVAL;
+	}
+
+	cmd = SPMI_APB_SPMI_CMD_EN |/*lint !e648 !e701 */								/* cmd_en */
+		 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |/*lint !e648 !e701 */			/* cmd_type */
+		 ((bc-1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |/*lint !e648 !e701 */		/* byte_cnt */
+		 ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |						/* slvid */
+		 ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);					/* slave_addr */
+
+	/* Write data to FIFOs */
+	spin_lock_irqsave(&spmi_controller->lock, flags);/*lint !e550 */
+
+	i = 0;
+	do {
+		memset(&data, 0, sizeof(data));
+		if ((bc - i*SPMI_PER_DATAREG_BYTE ) >> 2) {/*lint !e702 */
+			memcpy(&data, buf, sizeof(data));
+			buf +=sizeof(data);
+		} else {
+			memcpy(&data, buf, bc%SPMI_PER_DATAREG_BYTE);/*lint !e747 */
+			buf +=(bc%SPMI_PER_DATAREG_BYTE);
+		}
+
+		data = Tranverse32(data);
+		SPMI_WRITEL(spmi_controller->dev, data, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR+SPMI_PER_DATAREG_BYTE*i);
+		i++;
+	} while (bc > i*SPMI_PER_DATAREG_BYTE);
+
+	/* Start the transaction */
+	SPMI_WRITEL(spmi_controller->dev, cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+	rc = spmi_controller_wait_for_done(spmi_controller, spmi_controller->base, sid, addr);
+	spin_unlock_irqrestore(&spmi_controller->lock, flags);
+
+	if (rc)
+		dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
+							opc, sid, addr, bc);
+
+	return rc;
+}/*lint !e438 !e550 !e529*/
+/*lint +e438 -esym(438,*)*/
+static int spmi_controller_probe(struct platform_device *pdev)
+{
+	struct spmi_controller_dev *spmi_controller;
+	struct spmi_controller *ctrl;
+	struct resource *iores;
+	int ret = 0;
+
+	printk(KERN_INFO "HISI SPMI probe\n");
+	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+	if (!ctrl) {
+		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
+		return -ENOMEM;  /*lint !e429*/
+	}
+	spmi_controller = spmi_controller_get_drvdata(ctrl);
+	spmi_controller->controller = ctrl;
+
+	/* NOTE: driver uses the static register mapping */
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores) {
+		dev_err(&pdev->dev, "can not get resource! \n");
+		return -EINVAL; /*lint !e429*/
+	}
+
+	spmi_controller->base = ioremap(iores->start, resource_size(iores));
+	if (!spmi_controller->base) {
+		dev_err(&pdev->dev, "can not remap base addr! \n");
+		return -EADDRNOTAVAIL; /*lint !e429*/
+	}
+	dev_dbg(&pdev->dev, "spmi_add_controller base addr=0x%lx!\n", (long unsigned int)spmi_controller->base);/*lint !e774*/
+
+	/* Get properties from the device tree */
+	ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
+			&spmi_controller->channel);/*lint !e838*/
+	if (ret) {
+		dev_err(&pdev->dev, "can not get chanel \n");
+		return -ENODEV; /*lint !e429*/
+	}
+
+	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!\n");
+		goto err_add_controller;
+	}
+err_add_controller:
+	platform_set_drvdata(pdev, NULL);
+	return ret; /*lint !e429*/
+}
+
+static int spmi_del_controller(struct platform_device *pdev)
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	spmi_controller_remove(ctrl);
+	return 0;
+}
+
+static struct of_device_id spmi_controller_match_table[] = {
+	{	.compatible = "hisilicon,spmi-controller",
+	},/*lint !e785*/
+	{}/*lint !e785*/
+};
+
+static struct platform_driver spmi_controller_driver = {
+	.probe		= spmi_controller_probe,
+	.remove		= spmi_del_controller,
+	.driver		= {
+		.name	= SPMI_CONTROLLER_NAME,
+		.owner	= THIS_MODULE,/*lint !e64*/
+		.of_match_table = spmi_controller_match_table,
+	},/*lint !e785*/
+};/*lint !e785*/
+/*lint -e528 -esym(528,*)*/
+static int __init spmi_controller_init(void)
+{
+	return platform_driver_register(&spmi_controller_driver);/*lint !e64*/
+}
+postcore_initcall(spmi_controller_init);
+
+static void __exit spmi_controller_exit(void)
+{
+	platform_driver_unregister(&spmi_controller_driver);
+}
+module_exit(spmi_controller_exit);
+/*lint -e753 -esym(753,*)*/
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");/*lint !e785 !e64 !e528*/
+MODULE_ALIAS("platform:spmi_controlller");
+/*lint -e753 +esym(753,*)*/
+/*lint -e528 +esym(528,*)*/
+
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hisi_pmic.h
new file mode 100644
index 000000000000..939b36f617c1
--- /dev/null
+++ b/include/linux/mfd/hisi_pmic.h
@@ -0,0 +1,165 @@
+/*
+ * Header file for device driver Hi6421 PMIC
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef	__HISI_PMIC_H
+#define	__HISI_PMIC_H
+
+#include <linux/irqdomain.h>
+
+#define HISI_REGS_ENA_PROTECT_TIME	(0) 	/* in microseconds */
+#define HISI_ECO_MODE_ENABLE		(1)
+#define HISI_ECO_MODE_DISABLE		(0)
+
+typedef int (*pmic_ocp_callback)(char *);
+extern int hisi_pmic_special_ocp_register(char *power_name, pmic_ocp_callback handler);
+
+struct irq_mask_info {
+	int start_addr;
+	int array;
+};
+
+struct irq_info {
+	int start_addr;
+	int array;
+};
+
+struct bit_info {
+	int addr;
+	int bit;
+};
+
+struct write_lock {
+	int addr;
+	int val;
+};
+
+struct hisi_pmic {
+	struct resource		*res;
+	struct device		*dev;
+	void __iomem		*regs;
+	spinlock_t		lock;
+	struct irq_domain	*domain;
+	int			irq;
+	int			gpio;
+	unsigned int	*irqs;
+	int			irqnum;
+	int			irqarray;
+	struct irq_mask_info irq_mask_addr;
+	struct irq_info irq_addr;
+	int			irqnum1;
+	int			irqarray1;
+	struct irq_mask_info irq_mask_addr1;
+	struct irq_info irq_addr1;
+	struct write_lock normal_lock;
+	struct write_lock debug_lock;
+};
+
+/* 0:disable; 1:enable */
+unsigned int get_uv_mntn_status(void);
+void clear_uv_mntn_resered_reg_bit(void);
+void set_uv_mntn_resered_reg_bit(void);
+
+#if defined(CONFIG_HISI_PMIC) || defined(CONFIG_HISI_PMIC_PMU_SPMI)
+/* Register Access Helpers */
+u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
+void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val);
+void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits);
+unsigned int hisi_pmic_reg_read(int addr);
+void hisi_pmic_reg_write(int addr, int val);
+void hisi_pmic_reg_write_lock(int addr, int val);
+int hisi_pmic_array_read(int addr, char *buff, unsigned int len);
+int hisi_pmic_array_write(int addr, char *buff, unsigned int len);
+extern int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list);
+extern int hisi_pmic_get_vbus_status(void);
+#if defined(CONFIG_HISI_DIEID)
+u32 hisi_pmic_read_sub_pmu(u8 sid ,int reg);
+void hisi_pmic_write_sub_pmu(u8 sid ,int reg, u32 val);
+#endif
+#else
+static inline u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg) { return 0; }
+static inline void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val) {}
+static inline void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits) {}
+static inline unsigned int hisi_pmic_reg_read(int addr) { return 0; }
+static inline void hisi_pmic_reg_write(int addr, int val) {}
+static inline void hisi_pmic_reg_write_lock(int addr, int val) {}
+static inline int hisi_pmic_array_read(int addr, char *buff, unsigned int len) { return 0; }
+static inline int hisi_pmic_array_write(int addr, char *buff, unsigned int len) { return 0; }
+static inline int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list) { return -1; }
+static inline int hisi_pmic_get_vbus_status(void) { return 1; }
+static inline u32 hisi_pmic_read_sub_pmu(u8 sid ,int reg) { return 0; }
+static inline void hisi_pmic_write_sub_pmu(u8 sid ,int reg, u32 val) {}
+#endif
+
+#ifdef CONFIG_HISI_HI6421V500_PMU
+enum pmic_irq_list {
+	POR_D45MR = 0,
+	VBUS_CONNECT,
+	VBUS_DISCONNECT,
+	ALARMON_R,
+	HOLD_6S,
+	HOLD_1S,
+	POWERKEY_UP,
+	POWERKEY_DOWN,
+	OCP_SCP_R,
+	COUL_R,
+	VSYS_OV,
+	VSYS_UV,
+	VSYS_PWROFF_ABS,
+	VSYS_PWROFF_DEB,
+	THSD_OTMP140,
+	THSD_OTMP125,
+	HRESETN,
+	SIM0_HPD_R = 24,
+	SIM0_HPD_F,
+	SIM0_HPD_H,
+	SIM0_HPD_L,
+	SIM1_HPD_R,
+	SIM1_HPD_F,
+	SIM1_HPD_H,
+	SIM1_HPD_L,
+	PMIC_IRQ_LIST_MAX,
+};
+#else
+enum pmic_irq_list {
+	OTMP = 0,
+	VBUS_CONNECT,
+	VBUS_DISCONNECT,
+	ALARMON_R,
+	HOLD_6S,
+	HOLD_1S,
+	POWERKEY_UP,
+	POWERKEY_DOWN,
+	OCP_SCP_R,
+	COUL_R,
+	SIM0_HPD_R,
+	SIM0_HPD_F,
+	SIM1_HPD_R,
+	SIM1_HPD_F,
+	PMIC_IRQ_LIST_MAX,
+};
+#endif
+
+#ifdef CONFIG_HISI_SR_DEBUG
+extern void get_ip_regulator_state(void);
+#endif
+#endif		/* __HISI_PMIC_H */
+
-- 
2.26.2


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

* [PATCH 03/33] spmi: hisi-spmi-controller: coding style fixup
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 01/33] spmi: get rid of a warning when built with W=1 Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC Mauro Carvalho Chehab
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

In order to prepare for upstream, fix most coding style issues.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 179 +++++++++++++---------------
 1 file changed, 82 insertions(+), 97 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 987526c8b49f..3af0bd1b379f 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -21,7 +22,7 @@
 #define SPMI_SLAVE_OFFSET						0x20
 
 #define SPMI_APB_SPMI_CMD_BASE_ADDR				0x0100
-/*lint -e750 -esym(750,*)*/
+
 #define SPMI_APB_SPMI_WDATA0_BASE_ADDR			0x0104
 #define SPMI_APB_SPMI_WDATA1_BASE_ADDR			0x0108
 #define SPMI_APB_SPMI_WDATA2_BASE_ADDR			0x010c
@@ -33,25 +34,25 @@
 #define SPMI_APB_SPMI_RDATA1_BASE_ADDR			0x0208
 #define SPMI_APB_SPMI_RDATA2_BASE_ADDR			0x020c
 #define SPMI_APB_SPMI_RDATA3_BASE_ADDR			0x0210
-/*lint +e750 -esym(750,*)*/
 
 #define SPMI_PER_DATAREG_BYTE					4
 /*
  * SPMI cmd register
  */
-#define SPMI_APB_SPMI_CMD_EN						(1 << 31)
+#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
 
-#define Tranverse32(X)                 ((((u32)(X) & 0xff000000) >> 24) | \
-							   (((u32)(X) & 0x00ff0000) >> 8) | \
-							   (((u32)(X) & 0x0000ff00) << 8) | \
-							   (((u32)(X) & 0x000000ff) << 24))
+#define bswap_32(X)   \
+    ((((u32)(X) & 0xff000000) >> 24) | \
+     (((u32)(X) & 0x00ff0000) >> 8) | \
+     (((u32)(X) & 0x0000ff00) << 8) | \
+     (((u32)(X) & 0x000000ff) << 24))
 
 /* Command Opcodes */
-/*lint -e749 -esym(749,*)*/
+
 enum spmi_controller_cmd_op_code {
 	SPMI_CMD_REG_ZERO_WRITE = 0,
 	SPMI_CMD_REG_WRITE = 1,
@@ -65,13 +66,12 @@ enum spmi_controller_cmd_op_code {
 	SPMI_CMD_REG_SHUTDOWN = 9,
 	SPMI_CMD_REG_WAKEUP = 10,
 };
-/*lint +e749 -esym(749,*)*/
 
 /*
  * SPMI status register
  */
-#define SPMI_APB_TRANS_DONE						(1 << 0)
-#define SPMI_APB_TRANS_FAIL						(1 << 2)
+#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
@@ -80,16 +80,6 @@ enum spmi_controller_cmd_op_code {
 #define SPMI_CONTROLLER_TIMEOUT_US		1000
 #define SPMI_CONTROLLER_MAX_TRANS_BYTES	(16)
 
-#define SPMI_WRITEL( dev, reg, addr )	\
-	do { \
-		writel( ( reg ), ( addr ) ); \
-	} while (0)
-
-#define  SPMI_READL( dev, reg, addr )	\
-	do { \
-		reg = readl( addr ); \
-	} while (0)
-
 /*
  * @base base address of the PMIC Arbiter core registers.
  * @rdbase, @wrbase base address of the PMIC Arbiter read core registers.
@@ -120,7 +110,7 @@ struct spmi_controller_dev {
 };
 
 static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
-				  void __iomem *base, u8 sid, u16 addr)
+					 void __iomem *base, u8 sid, u16 addr)
 {
 	u32 status = 0;
 	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
@@ -128,7 +118,7 @@ static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
 		+ SPMI_SLAVE_OFFSET * sid;
 
 	while (timeout--) {
-		SPMI_READL(ctrl_dev->dev, status, base + offset);/*lint !e732 */
+		status = readl(base + offset);
 
 		if (status & SPMI_APB_TRANS_DONE) {
 			if (status & SPMI_APB_TRANS_FAIL) {
@@ -139,23 +129,23 @@ static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
 			}
 			return 0;
 		}
-		udelay(1);/*lint !e778 !e774 !e747*/
+		udelay(1);
 	}
 
 	dev_err(ctrl_dev->dev,
 		"%s: timeout, status 0x%x\n",
 		__func__, status);
-	return -ETIMEDOUT;/*lint !e438*/
-}/*lint !e715 !e529*/
+	return -ETIMEDOUT;
+}
 
 static int spmi_read_cmd(struct spmi_controller *ctrl,
-				u8 opc, u8 sid, u16 addr, u8 *buf, size_t bc)
+			 u8 opc, u8 sid, u16 addr, u8 *buf, size_t bc)
 {
 	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
 	unsigned long flags;
 	u32 cmd, data;
 	int rc;
-	u32 chnl_ofst = SPMI_CHANNEL_OFFSET*spmi_controller->channel;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
 	u8 op_code, i;
 
 	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
@@ -166,27 +156,26 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 	}
 
 	/* Check the opcode */
-	if (SPMI_CMD_READ == opc)
+	if (opc == SPMI_CMD_READ) {
 		op_code = SPMI_CMD_REG_READ;
-	else if (SPMI_CMD_EXT_READ == opc)
+	} else if (opc == SPMI_CMD_EXT_READ) {
 		op_code = SPMI_CMD_EXT_REG_READ;
-	else if (SPMI_CMD_EXT_READL == opc)
+	} else if (opc == SPMI_CMD_EXT_READL) {
 		op_code = SPMI_CMD_EXT_REG_READ_L;
-	else {
+	} else {
 		dev_err(spmi_controller->dev, "invalid read cmd 0x%x", opc);
 		return -EINVAL;
 	}
 
-	cmd = SPMI_APB_SPMI_CMD_EN |/*lint !e648 !e701 */								/* cmd_en */
-		 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |/*lint !e648 !e701 */			/* cmd_type */
-		 ((bc-1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |/*lint !e648 !e701 */		/* byte_cnt */
-		 ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |						/* slvid */
-		 ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);					/* slave_addr */
+	cmd = SPMI_APB_SPMI_CMD_EN |
+	     (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+	     ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+	     ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+	     ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
 
-	spin_lock_irqsave(&spmi_controller->lock, flags);/*lint !e550 */
-
-	SPMI_WRITEL(spmi_controller->dev, cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_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(spmi_controller, spmi_controller->base, sid, addr);
 	if (rc)
@@ -194,39 +183,37 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 
 	i = 0;
 	do {
-		SPMI_READL(spmi_controller->dev, data, spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET*sid + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i*SPMI_PER_DATAREG_BYTE);/*lint !e732 */
-		data = Tranverse32(data);
-		if ((bc - i*SPMI_PER_DATAREG_BYTE ) >> 2) {/*lint !e702 */
+		data = readl(spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET * sid + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i * SPMI_PER_DATAREG_BYTE);
+		data = bswap_32(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);/*lint !e747 */
-			buf += (bc%SPMI_PER_DATAREG_BYTE);
+			memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
+			buf += (bc % SPMI_PER_DATAREG_BYTE);
 		}
 		i++;
-	} while (bc > i*SPMI_PER_DATAREG_BYTE);
+	} while (bc > i * SPMI_PER_DATAREG_BYTE);
 
 done:
 	spin_unlock_irqrestore(&spmi_controller->lock, flags);
 	if (rc)
 		dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
-							opc, sid, addr, bc + 1);
+			opc, sid, addr, bc + 1);
 	return rc;
-}/*lint !e550 !e529*/
+}
 
-/*lint -e438 -esym(438,*)*/
 static int spmi_write_cmd(struct spmi_controller *ctrl,
-				u8 opc, u8 sid, u16 addr, const u8 *buf, size_t bc)
+			  u8 opc, u8 sid, u16 addr, const u8 *buf, size_t bc)
 {
 	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
 	unsigned long flags;
 	u32 cmd;
 	u32 data = 0;
 	int rc;
-	u32 chnl_ofst = SPMI_CHANNEL_OFFSET*spmi_controller->channel;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
 	u8 op_code, i;
 
-
 	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
 		dev_err(spmi_controller->dev
 		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
@@ -235,55 +222,55 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 	}
 
 	/* Check the opcode */
-	if (SPMI_CMD_WRITE == opc)
+	if (opc == SPMI_CMD_WRITE) {
 		op_code = SPMI_CMD_REG_WRITE;
-	else if (SPMI_CMD_EXT_WRITE == opc)
+	} else if (opc == SPMI_CMD_EXT_WRITE) {
 		op_code = SPMI_CMD_EXT_REG_WRITE;
-	else if (SPMI_CMD_EXT_WRITEL == opc)
+	} else if (opc == SPMI_CMD_EXT_WRITEL) {
 		op_code = SPMI_CMD_EXT_REG_WRITE_L;
-	else {
+	} else {
 		dev_err(spmi_controller->dev, "invalid write cmd 0x%x", opc);
 		return -EINVAL;
 	}
 
-	cmd = SPMI_APB_SPMI_CMD_EN |/*lint !e648 !e701 */								/* cmd_en */
-		 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |/*lint !e648 !e701 */			/* cmd_type */
-		 ((bc-1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |/*lint !e648 !e701 */		/* byte_cnt */
-		 ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |						/* slvid */
-		 ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);					/* slave_addr */
+	cmd = SPMI_APB_SPMI_CMD_EN |
+	      (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+	      ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+	      ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+	      ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
 
 	/* Write data to FIFOs */
-	spin_lock_irqsave(&spmi_controller->lock, flags);/*lint !e550 */
+	spin_lock_irqsave(&spmi_controller->lock, flags);
 
 	i = 0;
 	do {
 		memset(&data, 0, sizeof(data));
-		if ((bc - i*SPMI_PER_DATAREG_BYTE ) >> 2) {/*lint !e702 */
+		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
 			memcpy(&data, buf, sizeof(data));
-			buf +=sizeof(data);
+			buf += sizeof(data);
 		} else {
-			memcpy(&data, buf, bc%SPMI_PER_DATAREG_BYTE);/*lint !e747 */
-			buf +=(bc%SPMI_PER_DATAREG_BYTE);
+			memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
+			buf += (bc % SPMI_PER_DATAREG_BYTE);
 		}
 
-		data = Tranverse32(data);
-		SPMI_WRITEL(spmi_controller->dev, data, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR+SPMI_PER_DATAREG_BYTE*i);
+		data = bswap_32(data);
+		writel(data, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR + SPMI_PER_DATAREG_BYTE * i);
 		i++;
-	} while (bc > i*SPMI_PER_DATAREG_BYTE);
+	} while (bc > i * SPMI_PER_DATAREG_BYTE);
 
 	/* Start the transaction */
-	SPMI_WRITEL(spmi_controller->dev, cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
 
 	rc = spmi_controller_wait_for_done(spmi_controller, spmi_controller->base, sid, addr);
 	spin_unlock_irqrestore(&spmi_controller->lock, flags);
 
 	if (rc)
 		dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
-							opc, sid, addr, bc);
+			opc, sid, addr, bc);
 
 	return rc;
-}/*lint !e438 !e550 !e529*/
-/*lint +e438 -esym(438,*)*/
+}
+
 static int spmi_controller_probe(struct platform_device *pdev)
 {
 	struct spmi_controller_dev *spmi_controller;
@@ -291,11 +278,11 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	struct resource *iores;
 	int ret = 0;
 
-	printk(KERN_INFO "HISI SPMI probe\n");
+	dev_info(&pdev->dev, "HISI SPMI probe\n");
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
 	if (!ctrl) {
 		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
-		return -ENOMEM;  /*lint !e429*/
+		return -ENOMEM;
 	}
 	spmi_controller = spmi_controller_get_drvdata(ctrl);
 	spmi_controller->controller = ctrl;
@@ -303,23 +290,24 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	/* NOTE: driver uses the static register mapping */
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!iores) {
-		dev_err(&pdev->dev, "can not get resource! \n");
-		return -EINVAL; /*lint !e429*/
+		dev_err(&pdev->dev, "can not get resource!\n");
+		return -EINVAL;
 	}
 
 	spmi_controller->base = ioremap(iores->start, resource_size(iores));
 	if (!spmi_controller->base) {
-		dev_err(&pdev->dev, "can not remap base addr! \n");
-		return -EADDRNOTAVAIL; /*lint !e429*/
+		dev_err(&pdev->dev, "can not remap base addr!\n");
+		return -EADDRNOTAVAIL;
 	}
-	dev_dbg(&pdev->dev, "spmi_add_controller base addr=0x%lx!\n", (long unsigned int)spmi_controller->base);/*lint !e774*/
+	dev_dbg(&pdev->dev, "spmi_add_controller base addr=0x%lx!\n",
+		(unsigned long)spmi_controller->base);
 
 	/* Get properties from the device tree */
 	ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
-			&spmi_controller->channel);/*lint !e838*/
+				   &spmi_controller->channel);
 	if (ret) {
-		dev_err(&pdev->dev, "can not get chanel \n");
-		return -ENODEV; /*lint !e429*/
+		dev_err(&pdev->dev, "can not get chanel\n");
+		return -ENODEV;
 	}
 
 	platform_set_drvdata(pdev, spmi_controller);
@@ -342,7 +330,7 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	}
 err_add_controller:
 	platform_set_drvdata(pdev, NULL);
-	return ret; /*lint !e429*/
+	return ret;
 }
 
 static int spmi_del_controller(struct platform_device *pdev)
@@ -354,10 +342,10 @@ static int spmi_del_controller(struct platform_device *pdev)
 	return 0;
 }
 
-static struct of_device_id spmi_controller_match_table[] = {
+static const struct of_device_id spmi_controller_match_table[] = {
 	{	.compatible = "hisilicon,spmi-controller",
-	},/*lint !e785*/
-	{}/*lint !e785*/
+	},
+	{}
 };
 
 static struct platform_driver spmi_controller_driver = {
@@ -365,14 +353,14 @@ static struct platform_driver spmi_controller_driver = {
 	.remove		= spmi_del_controller,
 	.driver		= {
 		.name	= SPMI_CONTROLLER_NAME,
-		.owner	= THIS_MODULE,/*lint !e64*/
+		.owner	= THIS_MODULE,
 		.of_match_table = spmi_controller_match_table,
-	},/*lint !e785*/
-};/*lint !e785*/
-/*lint -e528 -esym(528,*)*/
+	},
+};
+
 static int __init spmi_controller_init(void)
 {
-	return platform_driver_register(&spmi_controller_driver);/*lint !e64*/
+	return platform_driver_register(&spmi_controller_driver);
 }
 postcore_initcall(spmi_controller_init);
 
@@ -381,10 +369,7 @@ static void __exit spmi_controller_exit(void)
 	platform_driver_unregister(&spmi_controller_driver);
 }
 module_exit(spmi_controller_exit);
-/*lint -e753 -esym(753,*)*/
+
 MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");/*lint !e785 !e64 !e528*/
+MODULE_VERSION("1.0");
 MODULE_ALIAS("platform:spmi_controlller");
-/*lint -e753 +esym(753,*)*/
-/*lint -e528 +esym(528,*)*/
-
-- 
2.26.2


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

* [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 03/33] spmi: hisi-spmi-controller: coding style fixup Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 16:00   ` Mark Brown
  2020-08-11 15:41 ` [PATCH 05/33] regulator: hisi_regulator_spmi: port it to upstream Mauro Carvalho Chehab
                   ` (30 subsequent siblings)
  34 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Liam Girdwood, Mark Brown, linux-kernel

There are some checks there which could make sense for
downstream builds, but doesn't make much sense for
upstream ones. They came from the official Hikey970 tree
from Linaro, but even there, the commented-out code is not
set via other Kconfig vars.

So, let's just get rid of that. If needed later, this
patch can be (partially?) reversed.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hisi_pmic_spmi.c            |  63 --------
 drivers/regulator/hisi_regulator_spmi.c | 196 +-----------------------
 include/linux/mfd/hisi_pmic.h           |  42 -----
 3 files changed, 8 insertions(+), 293 deletions(-)

diff --git a/drivers/mfd/hisi_pmic_spmi.c b/drivers/mfd/hisi_pmic_spmi.c
index 6bb0bc4b203b..809381eb6043 100644
--- a/drivers/mfd/hisi_pmic_spmi.c
+++ b/drivers/mfd/hisi_pmic_spmi.c
@@ -53,10 +53,6 @@
 #define HISI_PMIC_FIRST_GROUP_INT_NUM        2
 
 static struct bit_info g_pmic_vbus = {0};
-#ifndef BIT
-#define BIT(x)		(0x1U << (x))
-#endif
-
 static struct hisi_pmic *g_pmic;
 static unsigned int g_extinterrupt_flag  = 0;
 static struct of_device_id of_hisi_pmic_match_tbl[] = {
@@ -121,65 +117,6 @@ void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
 }
 EXPORT_SYMBOL(hisi_pmic_write);
 
-#ifdef CONFIG_HISI_DIEID
-u32 hisi_pmic_read_sub_pmu(u8 sid, int reg)
-{
-	u32 ret;
-	u8 read_value = 0;
-	struct spmi_device *pdev;
-
-	if(strstr(saved_command_line, "androidboot.swtype=factory"))
-	{
-		if (NULL == g_pmic) {
-			pr_err(" g_pmic  is NULL\n");
-			return -1;/*lint !e570 */
-		}
-
-		pdev = to_spmi_device(g_pmic->dev);
-		if (NULL == pdev) {
-			pr_err("%s:pdev get failed!\n", __func__);
-			return -1;/*lint !e570 */
-		}
-
-		ret = spmi_ext_register_readl(pdev->ctrl, sid, reg, (unsigned char*)&read_value, 1);/*lint !e734 !e732 */
-		if (ret) {
-			pr_err("%s:spmi_ext_register_readl failed!\n", __func__);
-			return ret;
-		}
-		return (u32)read_value;
-	}
-	return  0;
-}
-EXPORT_SYMBOL(hisi_pmic_read_sub_pmu);
-
-void hisi_pmic_write_sub_pmu(u8 sid, int reg, u32 val)
-{
-	u32 ret;
-	struct spmi_device *pdev;
-	if(strstr(saved_command_line, "androidboot.swtype=factory"))
-	{
-		if (NULL == g_pmic) {
-			pr_err(" g_pmic  is NULL\n");
-			return;
-		}
-
-		pdev = to_spmi_device(g_pmic->dev);
-		if (NULL == pdev) {
-			pr_err("%s:pdev get failed!\n", __func__);
-			return;
-		}
-
-		ret = spmi_ext_register_writel(pdev->ctrl, sid, reg, (unsigned char*)&val, 1);/*lint !e734 !e732 */
-		if (ret) {
-			pr_err("%s:spmi_ext_register_writel failed!\n", __func__);
-			return ;
-		}
-	}
-
-	return ;
-}
-EXPORT_SYMBOL(hisi_pmic_write_sub_pmu);
-#endif
 
 void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg,
 		     u32 mask, u32 bits)
diff --git a/drivers/regulator/hisi_regulator_spmi.c b/drivers/regulator/hisi_regulator_spmi.c
index 941bfe32bf5b..7bc0ae27b110 100644
--- a/drivers/regulator/hisi_regulator_spmi.c
+++ b/drivers/regulator/hisi_regulator_spmi.c
@@ -34,19 +34,10 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/version.h>
-#ifdef CONFIG_HISI_PMIC_DEBUG
-#include <linux/debugfs.h>
-#endif
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/spmi.h>
 
-#if 1
-#define BRAND_DEBUG(args...) pr_debug(args);
-#else
-#define BRAND_DEBUG(args...)
-#endif
-
 struct hisi_regulator_register_info {
 	u32 ctrl_reg;
 	u32 enable_mask;
@@ -110,7 +101,7 @@ static int hisi_regulator_is_enabled(struct regulator_dev *dev)
 	struct hisi_pmic *pmic = rdev_to_pmic(dev);
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n", __func__, sreg->register_info.ctrl_reg,\
+	pr_debug("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n", __func__, sreg->register_info.ctrl_reg,\
 			(reg_val & sreg->register_info.enable_mask));
 
 	return ((reg_val & sreg->register_info.enable_mask) != 0);
@@ -124,7 +115,7 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 	/* keep a distance of off_on_delay from last time disabled */
 	ensured_time_after(sreg->last_off_time, sreg->off_on_delay);
 
-	BRAND_DEBUG("<[%s]: off_on_delay=%dus>\n", __func__, sreg->off_on_delay);
+	pr_debug("<[%s]: off_on_delay=%dus>\n", __func__, sreg->off_on_delay);
 
 	/* cannot enable more than one regulator at one time */
 	mutex_lock(&enable_mutex);
@@ -134,7 +125,7 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
 				sreg->register_info.enable_mask,
 				sreg->register_info.enable_mask);
-	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n", __func__, sreg->register_info.ctrl_reg,\
+	pr_debug("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n", __func__, sreg->register_info.ctrl_reg,\
 			sreg->register_info.enable_mask);
 
 	do_gettimeofday(&last_enabled);
@@ -165,7 +156,7 @@ static int hisi_regulator_get_voltage(struct regulator_dev *dev)
 
 	/* get voltage selector */
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.vset_reg);
-	BRAND_DEBUG("<[%s]: vset_reg=0x%x>\n", __func__, sreg->register_info.vset_reg);
+	pr_debug("<[%s]: vset_reg=0x%x>\n", __func__, sreg->register_info.vset_reg);
 
 	selector = (reg_val & sreg->register_info.vset_mask) >>
 				(ffs(sreg->register_info.vset_mask) - 1);
@@ -198,7 +189,7 @@ static int hisi_regulator_set_voltage(struct regulator_dev *dev,
 		sreg->register_info.vset_mask,
 		vsel << (ffs(sreg->register_info.vset_mask) - 1));
 
-	BRAND_DEBUG("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n", __func__,\
+	pr_debug("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n", __func__,\
 			sreg->register_info.vset_reg,\
 			sreg->register_info.vset_mask,\
 			vsel << (ffs(sreg->register_info.vset_mask) - 1)\
@@ -214,7 +205,7 @@ static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
 	u32 reg_val;
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	BRAND_DEBUG("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n", __func__, reg_val,\
+	pr_debug("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n", __func__, reg_val,\
 			sreg->register_info.ctrl_reg,\
 			sreg->register_info.eco_mode_mask\
 		   );
@@ -248,7 +239,7 @@ static int hisi_regulator_set_mode(struct regulator_dev *dev,
 		sreg->register_info.eco_mode_mask,
 		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
 
-	BRAND_DEBUG("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n", __func__,\
+	pr_debug("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n", __func__,\
 			sreg->register_info.ctrl_reg,\
 			sreg->register_info.eco_mode_mask,\
 			eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1)\
@@ -403,147 +394,6 @@ static struct of_device_id of_hisi_regulator_match_tbl[] = {
 	{ /* end */ }
 };
 
-#ifdef CONFIG_HISI_PMIC_DEBUG
-extern void get_current_regulator_dev(struct seq_file *s);
-extern void set_regulator_state(char *ldo_name, int value);
-extern void get_regulator_state(char *ldo_name);
-extern int set_regulator_voltage(char *ldo_name, unsigned int vol_value);
-
-u32 pmu_atoi(char *s)
-{
-	char *p = s;
-	char c;
-	u64 ret = 0;
-	if (s == NULL)
-		return 0;
-	while ((c = *p++) != '\0') {
-		if ('0' <= c && c <= '9') {
-			ret *= 10;
-			ret += (u64)((unsigned char)c - '0');
-			if (ret > U32_MAX)
-				return 0;
-		} else {
-			break;
-		}
-	}
-	return (u32)ret;
-}
-static int dbg_hisi_regulator_show(struct seq_file *s, void *data)
-{
-	seq_printf(s, "\n\r");
-	seq_printf(s, "%-13s %-15s %-15s %-15s %-15s\n\r",
-			"LDO_NAME", "ON/OFF", "Use_count", "Open_count", "Always_on");
-	seq_printf(s, "-----------------------------------------"
-			"-----------------------------------------------\n\r");
-	get_current_regulator_dev(s);
-	return 0;
-}
-
-static int dbg_hisi_regulator_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, dbg_hisi_regulator_show, inode->i_private);
-}
-
-static const struct file_operations debug_regulator_state_fops = {
-	.open		= dbg_hisi_regulator_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int dbg_control_regulator_show(struct seq_file *s, void *data)
-{
-	printk("                                                                             \n\r \
-		---------------------------------------------------------------------------------\n\r \
-		|usage:                                                                         |\n\r \
-		|	S = state	R = read	V = voltage                                         |\n\r \
-		|	set ldo state and voltage                                                   |\n\r \
-		|	get ldo state and current voltage                                           |\n\r \
-		|example:                                                                       |\n\r \
-		|	echo S ldo16 0   > control_regulator	:disable ldo16                      |\n\r \
-		|	echo S ldo16 1   > control_regulator	:enable ldo16                       |\n\r \
-		|	echo R ldo16     > control_regulator	:get ldo16 state and voltage        |\n\r \
-		|	echo V ldo16 xxx > control_regulator	:set ldo16 voltage                  |\n\r \
-		---------------------------------------------------------------------------------\n\r");
-	return 0;
-}
-static ssize_t dbg_control_regulator_set_value(struct file *filp, const char __user *buffer,
-	size_t count, loff_t *ppos)
-{
-	char tmp[128] = {0};
-	char ptr[128] = {0};
-	char *vol = NULL;
-	char num = 0;
-	unsigned int i;
-	int next_flag = 1;
-
-	if (count >= 128) {
-		pr_info("error! buffer size big than internal buffer\n");
-		return -EFAULT;
-	}
-
-	if (copy_from_user(tmp, buffer, count)) {
-		pr_info("error!\n");
-		return -EFAULT;
-	}
-
-	if (tmp[0] == 'R' || tmp[0] == 'r') {
-		for (i = 2; i < (count - 1); i++) {
-			ptr[i - 2] = tmp[i];
-		}
-		ptr[i - 2] = '\0';
-		get_regulator_state(ptr);
-	} else if (tmp[0] == 'S' || tmp[0] == 's') {
-		for (i = 2; i < (count - 1); i++) {
-			if (tmp[i] == ' ') {
-				next_flag = 0;
-				ptr[i - 2] = '\0';
-				continue;
-			}
-			if (next_flag) {
-				ptr[i - 2] = tmp[i];
-			} else {
-				num = tmp[i] - 48;
-			}
-		}
-		set_regulator_state(ptr, num);
-	} else if (tmp[0] == 'V' || tmp[0] == 'v') {
-		for (i = 2; i < (count - 1); i++) {
-			if (tmp[i] == ' ') {
-				next_flag = 0;
-				ptr[i - 2] = '\0';
-				continue;
-			}
-			if (next_flag) {
-				ptr[i - 2] = tmp[i];
-			} else {
-				vol = &tmp[i];
-				break;
-			}
-		}
-		set_regulator_voltage(ptr, pmu_atoi(vol));
-	}
-
-	*ppos += count;
-
-	return count;
-}
-
-static int dbg_control_regulator_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return single_open(file, dbg_control_regulator_show, &inode->i_private);
-}
-
-static const struct file_operations set_control_regulator_fops = {
-	.open		= dbg_control_regulator_open,
-	.read		= seq_read,
-	.write		= dbg_control_regulator_set_value,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-#endif
-
 static int hisi_regulator_probe(struct spmi_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -556,10 +406,6 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	const struct of_device_id *match;
 	struct regulation_constraints *constraint;
 	const char *supplyname = NULL;
-#ifdef CONFIG_HISI_PMIC_DEBUG
-	struct dentry *d;
-	static int debugfs_flag;
-#endif
 	unsigned int temp_modes;
 
 	const struct hisi_regulator *template = NULL;
@@ -572,11 +418,7 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	}
 
 	template = match->data;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0))
 	initdata = of_get_regulator_init_data(dev, np, NULL);
-#else
-	initdata = of_get_regulator_init_data(dev, np);
-#endif
 	if (NULL == initdata) {
 		pr_err("get regulator init data error !\n");
 		return -EINVAL;
@@ -636,32 +478,10 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 		goto hisi_probe_end;
 	}
 
-	BRAND_DEBUG("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n", rdesc->name,\
+	pr_debug("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n", rdesc->name,\
 			constraint->valid_modes_mask, constraint->valid_ops_mask);
 
 	dev_set_drvdata(dev, rdev);
-#ifdef CONFIG_HISI_PMIC_DEBUG
-	if (debugfs_flag == 0) {
-		d = debugfs_create_dir("hisi_regulator_debugfs", NULL);
-		if (!d) {
-			dev_err(dev, "failed to create hisi regulator debugfs dir !\n");
-			ret = -ENOMEM;
-			goto hisi_probe_fail;
-		}
-		(void) debugfs_create_file("regulator_state", S_IRUSR,
-						d, NULL, &debug_regulator_state_fops);
-
-		(void) debugfs_create_file("control_regulator", S_IRUSR,
-						d, NULL, &set_control_regulator_fops);
-		debugfs_flag = 1;
-	}
-#endif
-
-#ifdef CONFIG_HISI_PMIC_DEBUG
-hisi_probe_fail:
-	if (ret)
-		regulator_unregister(rdev);
-#endif
 hisi_probe_end:
 	if (ret)
 		kfree(sreg);
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hisi_pmic.h
index 939b36f617c1..5be9b4d3f207 100644
--- a/include/linux/mfd/hisi_pmic.h
+++ b/include/linux/mfd/hisi_pmic.h
@@ -78,7 +78,6 @@ unsigned int get_uv_mntn_status(void);
 void clear_uv_mntn_resered_reg_bit(void);
 void set_uv_mntn_resered_reg_bit(void);
 
-#if defined(CONFIG_HISI_PMIC) || defined(CONFIG_HISI_PMIC_PMU_SPMI)
 /* Register Access Helpers */
 u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
 void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val);
@@ -90,11 +89,6 @@ int hisi_pmic_array_read(int addr, char *buff, unsigned int len);
 int hisi_pmic_array_write(int addr, char *buff, unsigned int len);
 extern int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list);
 extern int hisi_pmic_get_vbus_status(void);
-#if defined(CONFIG_HISI_DIEID)
-u32 hisi_pmic_read_sub_pmu(u8 sid ,int reg);
-void hisi_pmic_write_sub_pmu(u8 sid ,int reg, u32 val);
-#endif
-#else
 static inline u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg) { return 0; }
 static inline void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val) {}
 static inline void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits) {}
@@ -107,38 +101,7 @@ static inline int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list) { return
 static inline int hisi_pmic_get_vbus_status(void) { return 1; }
 static inline u32 hisi_pmic_read_sub_pmu(u8 sid ,int reg) { return 0; }
 static inline void hisi_pmic_write_sub_pmu(u8 sid ,int reg, u32 val) {}
-#endif
 
-#ifdef CONFIG_HISI_HI6421V500_PMU
-enum pmic_irq_list {
-	POR_D45MR = 0,
-	VBUS_CONNECT,
-	VBUS_DISCONNECT,
-	ALARMON_R,
-	HOLD_6S,
-	HOLD_1S,
-	POWERKEY_UP,
-	POWERKEY_DOWN,
-	OCP_SCP_R,
-	COUL_R,
-	VSYS_OV,
-	VSYS_UV,
-	VSYS_PWROFF_ABS,
-	VSYS_PWROFF_DEB,
-	THSD_OTMP140,
-	THSD_OTMP125,
-	HRESETN,
-	SIM0_HPD_R = 24,
-	SIM0_HPD_F,
-	SIM0_HPD_H,
-	SIM0_HPD_L,
-	SIM1_HPD_R,
-	SIM1_HPD_F,
-	SIM1_HPD_H,
-	SIM1_HPD_L,
-	PMIC_IRQ_LIST_MAX,
-};
-#else
 enum pmic_irq_list {
 	OTMP = 0,
 	VBUS_CONNECT,
@@ -156,10 +119,5 @@ enum pmic_irq_list {
 	SIM1_HPD_F,
 	PMIC_IRQ_LIST_MAX,
 };
-#endif
-
-#ifdef CONFIG_HISI_SR_DEBUG
-extern void get_ip_regulator_state(void);
-#endif
 #endif		/* __HISI_PMIC_H */
 
-- 
2.26.2


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

* [PATCH 05/33] regulator: hisi_regulator_spmi: port it to upstream
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 06/33] mfd: hisi_pmic_spmi: deal with non-static functions Mauro Carvalho Chehab
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, Lee Jones, linux-kernel

The driver was originally written for Kernel 4.9. It needs to
be ported to upstream:

	- Got rid of timeval;
	- Removed a bogus dependency;
	- Did cleanups at the header file.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hisi_regulator_spmi.c | 34 ++++---------------------
 include/linux/mfd/hisi_pmic.h           | 26 -------------------
 2 files changed, 5 insertions(+), 55 deletions(-)

diff --git a/drivers/regulator/hisi_regulator_spmi.c b/drivers/regulator/hisi_regulator_spmi.c
index 7bc0ae27b110..904cb64b1dcd 100644
--- a/drivers/regulator/hisi_regulator_spmi.c
+++ b/drivers/regulator/hisi_regulator_spmi.c
@@ -49,7 +49,6 @@ struct hisi_regulator_register_info {
 struct hisi_regulator {
 	const char *name;
 	struct hisi_regulator_register_info register_info;
-	struct timeval last_off_time;
 	u32 off_on_delay;
 	u32 eco_uA;
 	struct regulator_desc rdesc;
@@ -57,8 +56,6 @@ struct hisi_regulator {
 };
 
 static DEFINE_MUTEX(enable_mutex);
-struct timeval last_enabled;
-
 
 static inline struct hisi_pmic *rdev_to_pmic(struct regulator_dev *dev)
 {
@@ -72,27 +69,6 @@ static inline struct hisi_pmic *rdev_to_pmic(struct regulator_dev *dev)
 /* helper function to ensure when it returns it is at least 'delay_us'
  * microseconds after 'since'.
  */
-static void ensured_time_after(struct timeval since, u32 delay_us)
-{
-	struct timeval now;
-	u64 elapsed_ns64, delay_ns64;
-	u32 actual_us32;
-
-	delay_ns64 = delay_us * NSEC_PER_USEC;
-	do_gettimeofday(&now);
-	elapsed_ns64 = timeval_to_ns(&now) - timeval_to_ns(&since);
-	if (delay_ns64 > elapsed_ns64) {
-		actual_us32 = ((u32)(delay_ns64 - elapsed_ns64) /
-							NSEC_PER_USEC);
-		if (actual_us32 >= 1000) {
-			mdelay(actual_us32 / 1000); /*lint !e647 */
-			udelay(actual_us32 % 1000);
-		} else if (actual_us32 > 0) {
-			udelay(actual_us32);
-		}
-	}
-	return;
-}
 
 static int hisi_regulator_is_enabled(struct regulator_dev *dev)
 {
@@ -113,13 +89,16 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 	struct hisi_pmic *pmic = rdev_to_pmic(dev);
 
 	/* keep a distance of off_on_delay from last time disabled */
-	ensured_time_after(sreg->last_off_time, sreg->off_on_delay);
+	usleep_range(sreg->off_on_delay, sreg->off_on_delay + 1000);
 
 	pr_debug("<[%s]: off_on_delay=%dus>\n", __func__, sreg->off_on_delay);
 
 	/* cannot enable more than one regulator at one time */
 	mutex_lock(&enable_mutex);
-	ensured_time_after(last_enabled, HISI_REGS_ENA_PROTECT_TIME);
+	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
+		     HISI_REGS_ENA_PROTECT_TIME + 1000);
+
+
 
 	/* set enable register */
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
@@ -128,7 +107,6 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 	pr_debug("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n", __func__, sreg->register_info.ctrl_reg,\
 			sreg->register_info.enable_mask);
 
-	do_gettimeofday(&last_enabled);
 	mutex_unlock(&enable_mutex);
 
 	return 0;
@@ -143,8 +121,6 @@ static int hisi_regulator_disable(struct regulator_dev *dev)
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
 				sreg->register_info.enable_mask, 0);
 
-	do_gettimeofday(&sreg->last_off_time);
-
 	return 0;
 }
 
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hisi_pmic.h
index 5be9b4d3f207..c3f6e59e2b7d 100644
--- a/include/linux/mfd/hisi_pmic.h
+++ b/include/linux/mfd/hisi_pmic.h
@@ -73,34 +73,9 @@ struct hisi_pmic {
 	struct write_lock debug_lock;
 };
 
-/* 0:disable; 1:enable */
-unsigned int get_uv_mntn_status(void);
-void clear_uv_mntn_resered_reg_bit(void);
-void set_uv_mntn_resered_reg_bit(void);
-
-/* Register Access Helpers */
 u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
 void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val);
 void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits);
-unsigned int hisi_pmic_reg_read(int addr);
-void hisi_pmic_reg_write(int addr, int val);
-void hisi_pmic_reg_write_lock(int addr, int val);
-int hisi_pmic_array_read(int addr, char *buff, unsigned int len);
-int hisi_pmic_array_write(int addr, char *buff, unsigned int len);
-extern int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list);
-extern int hisi_pmic_get_vbus_status(void);
-static inline u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg) { return 0; }
-static inline void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val) {}
-static inline void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits) {}
-static inline unsigned int hisi_pmic_reg_read(int addr) { return 0; }
-static inline void hisi_pmic_reg_write(int addr, int val) {}
-static inline void hisi_pmic_reg_write_lock(int addr, int val) {}
-static inline int hisi_pmic_array_read(int addr, char *buff, unsigned int len) { return 0; }
-static inline int hisi_pmic_array_write(int addr, char *buff, unsigned int len) { return 0; }
-static inline int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list) { return -1; }
-static inline int hisi_pmic_get_vbus_status(void) { return 1; }
-static inline u32 hisi_pmic_read_sub_pmu(u8 sid ,int reg) { return 0; }
-static inline void hisi_pmic_write_sub_pmu(u8 sid ,int reg, u32 val) {}
 
 enum pmic_irq_list {
 	OTMP = 0,
@@ -120,4 +95,3 @@ enum pmic_irq_list {
 	PMIC_IRQ_LIST_MAX,
 };
 #endif		/* __HISI_PMIC_H */
-
-- 
2.26.2


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

* [PATCH 06/33] mfd: hisi_pmic_spmi: deal with non-static functions
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 05/33] regulator: hisi_regulator_spmi: port it to upstream Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 07/33] mfd: hisi_pmic_spmi: get rid of the static vars Mauro Carvalho Chehab
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones, linux-kernel

Several functions aren't used outside the mfd driver. So,
either remove or make them static.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hisi_pmic_spmi.c | 147 ++++++-----------------------------
 1 file changed, 24 insertions(+), 123 deletions(-)

diff --git a/drivers/mfd/hisi_pmic_spmi.c b/drivers/mfd/hisi_pmic_spmi.c
index 809381eb6043..8b87d48b88b5 100644
--- a/drivers/mfd/hisi_pmic_spmi.c
+++ b/drivers/mfd/hisi_pmic_spmi.c
@@ -73,21 +73,21 @@ u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
 	u8 read_value = 0;
 	struct spmi_device *pdev;
 
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
+	if (!g_pmic) {
+		pr_err("%s: g_pmic is NULL\n", __func__);
 		return 0;
 	}
 
 	pdev = to_spmi_device(g_pmic->dev);
-	if (NULL == pdev) {
-		pr_err("%s:pdev get failed!\n", __func__);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
 		return 0;
 	}
 
 	ret = spmi_ext_register_readl(pdev, reg, (unsigned char*)&read_value, 1);/*lint !e734 !e732 */
 	if (ret) {
-		pr_err("%s:spmi_ext_register_readl failed!\n", __func__);
-		return ret;
+		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
+		return 0;
 	}
 	return (u32)read_value;
 }
@@ -98,34 +98,32 @@ void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
 	u32 ret;
 	struct spmi_device *pdev;
 
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
+	if (!g_pmic) {
+		pr_err("%s: g_pmic is NULL\n", __func__);
 		return;
 	}
 
 	pdev = to_spmi_device(g_pmic->dev);
-	if (NULL == pdev) {
-		pr_err("%s:pdev get failed!\n", __func__);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
 		return;
 	}
 
 	ret = spmi_ext_register_writel(pdev, reg, (unsigned char*)&val, 1);/*lint !e734 !e732 */
 	if (ret) {
-		pr_err("%s:spmi_ext_register_writel failed!\n", __func__);
-		return ;
+		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
+		return;
 	}
 }
 EXPORT_SYMBOL(hisi_pmic_write);
 
-
-void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg,
-		     u32 mask, u32 bits)
+void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits)
 {
 	u32 data;
 	unsigned long flags;
 
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
+	if (!g_pmic) {
+		pr_err("%s: g_pmic is NULL\n", __func__);
 		return;
 	}
 
@@ -137,75 +135,6 @@ void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg,
 }
 EXPORT_SYMBOL(hisi_pmic_rmw);
 
-unsigned int hisi_pmic_reg_read(int addr)
-{
-	return (unsigned int)hisi_pmic_read(g_pmic, addr);
-}
-EXPORT_SYMBOL(hisi_pmic_reg_read);
-
-void hisi_pmic_reg_write(int addr, int val)
-{
-	hisi_pmic_write(g_pmic, addr, val);
-}
-EXPORT_SYMBOL(hisi_pmic_reg_write);
-
-void hisi_pmic_reg_write_lock(int addr, int val)
-{
-	unsigned long flags;
-
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
-		return;
-	}
-
-	spin_lock_irqsave(&g_pmic->lock, flags);
-	hisi_pmic_write(g_pmic, g_pmic->normal_lock.addr, g_pmic->normal_lock.val);
-	hisi_pmic_write(g_pmic, g_pmic->debug_lock.addr, g_pmic->debug_lock.val);
-	hisi_pmic_write(g_pmic, addr, val);
-	hisi_pmic_write(g_pmic, g_pmic->normal_lock.addr, 0);
-	hisi_pmic_write(g_pmic, g_pmic->debug_lock.addr, 0);
-	spin_unlock_irqrestore(&g_pmic->lock, flags);
-}
-
-int hisi_pmic_array_read(int addr, char *buff, unsigned int len)
-{
-	unsigned int i;
-
-	if ((len > 32) || (NULL == buff)) {
-		return -EINVAL;
-	}
-
-	/*
-	 * Here is a bug in the pmu die.
-	 * the coul driver will read 4 bytes,
-	 * but the ssi bus only read 1 byte, and the pmu die
-	 * will make sampling 1/10669us about vol cur,so the driver
-	 * read the data is not the same sampling
-	 */
-	for (i = 0; i < len; i++)
-	{
-		*(buff + i) = hisi_pmic_reg_read(addr+i);
-	}
-
-	return 0;
-}
-
-int hisi_pmic_array_write(int addr, char *buff, unsigned int len)
-{
-    unsigned int i;
-
-	if ((len > 32) || (NULL == buff)) {
-		return -EINVAL;
-	}
-
-	for (i = 0; i < len; i++)
-	{
-		hisi_pmic_reg_write(addr+i, *(buff + i));
-	}
-
-	return 0;
-}
-
 static irqreturn_t hisi_irq_handler(int irq, void *data)
 {
 	struct hisi_pmic *pmic = (struct hisi_pmic *)data;
@@ -213,13 +142,13 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	int i, offset;
 
 	for (i = 0; i < pmic->irqarray; i++) {
-		pending = hisi_pmic_reg_read((i + pmic->irq_addr.start_addr));
+		pending = hisi_pmic_read(g_pmic, (i + pmic->irq_addr.start_addr));
 		pending &= HISI_MASK_FIELD;
 		if (pending != 0) {
 			pr_info("pending[%d]=0x%lx\n\r", i, pending);
 		}
 
-		hisi_pmic_reg_write((i + pmic->irq_addr.start_addr), pending);
+		hisi_pmic_write(g_pmic, (i + pmic->irq_addr.start_addr), pending);
 
 		/*solve powerkey order*/
 		if ((HISI_IRQ_KEY_NUM == i) && ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
@@ -237,13 +166,13 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	/*Handle the second group irq if analysis the second group irq from dtsi*/
 	if (1 == g_extinterrupt_flag){
 		for (i = 0; i < pmic->irqarray1; i++) {
-			pending = hisi_pmic_reg_read((i + pmic->irq_addr1.start_addr));
+			pending = hisi_pmic_read(g_pmic, (i + pmic->irq_addr1.start_addr));
 			pending &= HISI_MASK_FIELD;
 			if (pending != 0) {
 				pr_info("pending[%d]=0x%lx\n\r", i, pending);
 			}
 
-			hisi_pmic_reg_write((i + pmic->irq_addr1.start_addr), pending);
+			hisi_pmic_write(g_pmic, (i + pmic->irq_addr1.start_addr), pending);
 
 			if (pending) {
 				for_each_set_bit(offset, &pending, HISI_BITS)
@@ -276,9 +205,9 @@ static void hisi_irq_mask(struct irq_data *d)
 		offset += pmic->irq_mask_addr.start_addr;
 	}
 	spin_lock_irqsave(&g_pmic->lock, flags);
-	data = hisi_pmic_reg_read(offset);
+	data = hisi_pmic_read(g_pmic, offset);
 	data |= (1 << (irqd_to_hwirq(d) & 0x07));
-	hisi_pmic_reg_write(offset, data);
+	hisi_pmic_write(g_pmic, offset, data);
 	spin_unlock_irqrestore(&g_pmic->lock, flags);
 }
 
@@ -303,9 +232,9 @@ static void hisi_irq_unmask(struct irq_data *d)
 		offset += pmic->irq_mask_addr.start_addr;
 	}
 	spin_lock_irqsave(&g_pmic->lock, flags);
-	data = hisi_pmic_reg_read(offset);
-	data &= ~(1 << (irqd_to_hwirq(d) & 0x07)); /*lint !e502 */
-	hisi_pmic_reg_write(offset, data);
+	data = hisi_pmic_read(g_pmic, offset);
+	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
+	hisi_pmic_write(g_pmic, offset, data);
 	spin_unlock_irqrestore(&g_pmic->lock, flags);
 }
 
@@ -452,34 +381,6 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 	return ret;
 }/*lint -restore*/
 
-int hisi_get_pmic_irq_byname(unsigned int pmic_irq_list)
-{
-	if ( NULL == g_pmic ) {
-		pr_err("[%s]g_pmic is NULL\n", __func__);
-		return -1;
-	}
-
-	if (pmic_irq_list > (unsigned int)g_pmic->irqnum) {
-		pr_err("[%s]input pmic irq number is error.\n", __func__);
-		return -1;
-	}
-	pr_info("%s:g_pmic->irqs[%d]=%d\n", __func__, pmic_irq_list, g_pmic->irqs[pmic_irq_list]);
-	return (int)g_pmic->irqs[pmic_irq_list];
-}
-EXPORT_SYMBOL(hisi_get_pmic_irq_byname);
-
-int hisi_pmic_get_vbus_status(void)
-{
-	if (0 == g_pmic_vbus.addr)
-		return -1;
-
-	if (hisi_pmic_reg_read(g_pmic_vbus.addr) & BIT(g_pmic_vbus.bit))
-		return 1;
-
-	return 0;
-}
-EXPORT_SYMBOL(hisi_pmic_get_vbus_status);
-
 static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
 {
 	int i;
-- 
2.26.2


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

* [PATCH 07/33] mfd: hisi_pmic_spmi: get rid of the static vars
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (5 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 06/33] mfd: hisi_pmic_spmi: deal with non-static functions Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 08/33] spmi: hisi-spmi-controller: fix it to probe successfully Mauro Carvalho Chehab
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones, linux-kernel

There are several static vars inside this driver.

Get rid of them.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hisi_pmic_spmi.c  | 100 +++++++++++-----------------------
 include/linux/mfd/hisi_pmic.h |   2 +
 2 files changed, 34 insertions(+), 68 deletions(-)

diff --git a/drivers/mfd/hisi_pmic_spmi.c b/drivers/mfd/hisi_pmic_spmi.c
index 8b87d48b88b5..0986e24ad304 100644
--- a/drivers/mfd/hisi_pmic_spmi.c
+++ b/drivers/mfd/hisi_pmic_spmi.c
@@ -52,10 +52,7 @@
 /*define the first group interrupt register number*/
 #define HISI_PMIC_FIRST_GROUP_INT_NUM        2
 
-static struct bit_info g_pmic_vbus = {0};
-static struct hisi_pmic *g_pmic;
-static unsigned int g_extinterrupt_flag  = 0;
-static struct of_device_id of_hisi_pmic_match_tbl[] = {
+static const struct of_device_id of_hisi_pmic_match_tbl[] = {
 	{
 		.compatible = "hisilicon-hisi-pmic-spmi",
 	},
@@ -73,12 +70,7 @@ u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
 	u8 read_value = 0;
 	struct spmi_device *pdev;
 
-	if (!g_pmic) {
-		pr_err("%s: g_pmic is NULL\n", __func__);
-		return 0;
-	}
-
-	pdev = to_spmi_device(g_pmic->dev);
+	pdev = to_spmi_device(pmic->dev);
 	if (!pdev) {
 		pr_err("%s: pdev get failed!\n", __func__);
 		return 0;
@@ -98,12 +90,7 @@ void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
 	u32 ret;
 	struct spmi_device *pdev;
 
-	if (!g_pmic) {
-		pr_err("%s: g_pmic is NULL\n", __func__);
-		return;
-	}
-
-	pdev = to_spmi_device(g_pmic->dev);
+	pdev = to_spmi_device(pmic->dev);
 	if (!pdev) {
 		pr_err("%s: pdev get failed!\n", __func__);
 		return;
@@ -122,16 +109,11 @@ void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits)
 	u32 data;
 	unsigned long flags;
 
-	if (!g_pmic) {
-		pr_err("%s: g_pmic is NULL\n", __func__);
-		return;
-	}
-
-	spin_lock_irqsave(&g_pmic->lock, flags);
+	spin_lock_irqsave(&pmic->lock, flags);
 	data = hisi_pmic_read(pmic, reg) & ~mask;
 	data |= mask & bits;
 	hisi_pmic_write(pmic, reg, data);
-	spin_unlock_irqrestore(&g_pmic->lock, flags);
+	spin_unlock_irqrestore(&pmic->lock, flags);
 }
 EXPORT_SYMBOL(hisi_pmic_rmw);
 
@@ -142,13 +124,13 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	int i, offset;
 
 	for (i = 0; i < pmic->irqarray; i++) {
-		pending = hisi_pmic_read(g_pmic, (i + pmic->irq_addr.start_addr));
+		pending = hisi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
 		pending &= HISI_MASK_FIELD;
 		if (pending != 0) {
 			pr_info("pending[%d]=0x%lx\n\r", i, pending);
 		}
 
-		hisi_pmic_write(g_pmic, (i + pmic->irq_addr.start_addr), pending);
+		hisi_pmic_write(pmic, (i + pmic->irq_addr.start_addr), pending);
 
 		/*solve powerkey order*/
 		if ((HISI_IRQ_KEY_NUM == i) && ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
@@ -164,15 +146,15 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	}
 
 	/*Handle the second group irq if analysis the second group irq from dtsi*/
-	if (1 == g_extinterrupt_flag){
+	if (pmic->g_extinterrupt_flag == 1) {
 		for (i = 0; i < pmic->irqarray1; i++) {
-			pending = hisi_pmic_read(g_pmic, (i + pmic->irq_addr1.start_addr));
+			pending = hisi_pmic_read(pmic, (i + pmic->irq_addr1.start_addr));
 			pending &= HISI_MASK_FIELD;
 			if (pending != 0) {
 				pr_info("pending[%d]=0x%lx\n\r", i, pending);
 			}
 
-			hisi_pmic_write(g_pmic, (i + pmic->irq_addr1.start_addr), pending);
+			hisi_pmic_write(pmic, (i + pmic->irq_addr1.start_addr), pending);
 
 			if (pending) {
 				for_each_set_bit(offset, &pending, HISI_BITS)
@@ -190,25 +172,20 @@ static void hisi_irq_mask(struct irq_data *d)
 	u32 data, offset;
 	unsigned long flags;
 
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
-		return;
-	}
-
 	offset = (irqd_to_hwirq(d) >> 3);
-	if (1==g_extinterrupt_flag){
-		if ( offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
+	if (pmic->g_extinterrupt_flag == 1) {
+		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
 			offset += pmic->irq_mask_addr.start_addr;
 		else/*Change addr when irq num larger than 16 because interrupt addr is nonsequence*/
 			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
 	}else{
 		offset += pmic->irq_mask_addr.start_addr;
 	}
-	spin_lock_irqsave(&g_pmic->lock, flags);
-	data = hisi_pmic_read(g_pmic, offset);
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hisi_pmic_read(pmic, offset);
 	data |= (1 << (irqd_to_hwirq(d) & 0x07));
-	hisi_pmic_write(g_pmic, offset, data);
-	spin_unlock_irqrestore(&g_pmic->lock, flags);
+	hisi_pmic_write(pmic, offset, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
 }
 
 static void hisi_irq_unmask(struct irq_data *d)
@@ -217,25 +194,20 @@ static void hisi_irq_unmask(struct irq_data *d)
 	u32 data, offset;
 	unsigned long flags;
 
-	if (NULL == g_pmic) {
-		pr_err(" g_pmic  is NULL\n");
-		return;
-	}
-
 	offset = (irqd_to_hwirq(d) >> 3);
-	if (1==g_extinterrupt_flag){
-		if ( offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
+	if (pmic->g_extinterrupt_flag == 1) {
+		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
 			offset += pmic->irq_mask_addr.start_addr;
 		else
 			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
 	}else{
 		offset += pmic->irq_mask_addr.start_addr;
 	}
-	spin_lock_irqsave(&g_pmic->lock, flags);
-	data = hisi_pmic_read(g_pmic, offset);
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hisi_pmic_read(pmic, offset);
 	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
-	hisi_pmic_write(g_pmic, offset, data);
-	spin_unlock_irqrestore(&g_pmic->lock, flags);
+	hisi_pmic_write(pmic, offset, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
 }
 
 static struct irq_chip hisi_pmu_irqchip = {
@@ -305,14 +277,6 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 		return ret;
 	}
 
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-vbus",
-						(u32 *)&g_pmic_vbus, 2);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-vbus property\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
 	/*pmic lock*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-lock",
 						(int *)&pmic->normal_lock, 2);
@@ -377,7 +341,7 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 		return ret;
 	}
 
-	g_extinterrupt_flag = 1;
+	pmic->g_extinterrupt_flag = 1;
 	return ret;
 }/*lint -restore*/
 
@@ -399,13 +363,14 @@ static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
 static void hisi_pmic_irq1_prc(struct hisi_pmic *pmic)
 {
 	int i;
-	if(1 == g_extinterrupt_flag){
-		for (i = 0 ; i < pmic->irq_mask_addr1.array; i++) {
+	unsigned int pending1;
+
+	if (pmic->g_extinterrupt_flag == 1) {
+		for (i = 0 ; i < pmic->irq_mask_addr1.array; i++)
 			hisi_pmic_write(pmic, pmic->irq_mask_addr1.start_addr + i, HISI_MASK_STATE);
-		}
 
 		for (i = 0 ; i < pmic->irq_addr1.array; i++) {
-			unsigned int pending1 = hisi_pmic_read(pmic, pmic->irq_addr1.start_addr + i);
+			pending1 = hisi_pmic_read(pmic, pmic->irq_addr1.start_addr + i);
 			pr_debug("PMU IRQ address1 value:irq[0x%x] = 0x%x\n", pmic->irq_addr1.start_addr + i, pending1);
 			hisi_pmic_write(pmic, pmic->irq_addr1.start_addr + i, HISI_MASK_STATE);
 		}
@@ -446,11 +411,11 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	spin_lock_init(&pmic->lock);
 
 	pmic->dev = dev;
-	g_pmic = pmic;
-	ret = of_property_read_u32_array(np, "hisilicon,pmic_fpga_flag", &fpga_flag, 1);
-	if (ret) {
+	ret = of_property_read_u32_array(np, "hisilicon,pmic_fpga_flag",
+					 &fpga_flag, 1);
+	if (ret)
 		pr_err("no hisilicon,pmic_fpga_flag property set\n");
-	}
+
 	if (PMIC_FPGA_FLAG == fpga_flag) {
 		goto after_irq_register;
 	}
@@ -521,7 +486,6 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 irq_domain:
 irq_malloc:
 	gpio_free(pmic->gpio);
-	g_pmic = NULL;
 	return ret;
 }
 
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hisi_pmic.h
index c3f6e59e2b7d..b387575fb43c 100644
--- a/include/linux/mfd/hisi_pmic.h
+++ b/include/linux/mfd/hisi_pmic.h
@@ -71,6 +71,8 @@ struct hisi_pmic {
 	struct irq_info irq_addr1;
 	struct write_lock normal_lock;
 	struct write_lock debug_lock;
+
+	unsigned int g_extinterrupt_flag;
 };
 
 u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
-- 
2.26.2


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

* [PATCH 08/33] spmi: hisi-spmi-controller: fix it to probe successfully
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (6 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 07/33] mfd: hisi_pmic_spmi: get rid of the static vars Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 09/33] spmi: hisi-spmi-controller: fix a typo Mauro Carvalho Chehab
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

Add a MODULE_DEVICE_TABLE() to the driver.

Also, the current logic calls platform_set_drvdata(pdev, NULL)
if the driver succeeds loading.

While here, remove the .owner, as it is not needed upstream
anymore.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 3af0bd1b379f..bc6847f9a5e7 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -324,11 +324,14 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	ctrl->write_cmd = spmi_write_cmd;
 
 	ret = spmi_controller_add(ctrl);
-	if (ret) {
-		dev_err(&pdev->dev, "spmi_add_controller failed!\n");
+	if (ret)
 		goto err_add_controller;
-	}
+
+	dev_info(&pdev->dev, "spmi_add_controller initialized\n");
+	return 0;
+
 err_add_controller:
+	dev_err(&pdev->dev, "spmi_add_controller failed!\n");
 	platform_set_drvdata(pdev, NULL);
 	return ret;
 }
@@ -347,13 +350,13 @@ static const struct of_device_id spmi_controller_match_table[] = {
 	},
 	{}
 };
+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	= SPMI_CONTROLLER_NAME,
-		.owner	= THIS_MODULE,
 		.of_match_table = spmi_controller_match_table,
 	},
 };
-- 
2.26.2


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

* [PATCH 09/33] spmi: hisi-spmi-controller: fix a typo
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (7 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 08/33] spmi: hisi-spmi-controller: fix it to probe successfully Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 10/33] spmi: hisi-spmi-controller: adjust whitespaces at defines Mauro Carvalho Chehab
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

chanel -> channel

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index bc6847f9a5e7..99cf757d76fe 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -306,7 +306,7 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
 				   &spmi_controller->channel);
 	if (ret) {
-		dev_err(&pdev->dev, "can not get chanel\n");
+		dev_err(&pdev->dev, "can not get channel\n");
 		return -ENODEV;
 	}
 
-- 
2.26.2


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

* [PATCH 10/33] spmi: hisi-spmi-controller: adjust whitespaces at defines
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (8 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 09/33] spmi: hisi-spmi-controller: fix a typo Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 11/33] spmi: hisi-spmi-controller: use le32 macros where needed Mauro Carvalho Chehab
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

Some defines are not aligned with tab=8, which is the
style defined on Linux. Adjust them.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 99cf757d76fe..7fae267a6062 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -18,10 +18,10 @@
 /*
  * SPMI register addr
  */
-#define SPMI_CHANNEL_OFFSET					0x0300
-#define SPMI_SLAVE_OFFSET						0x20
+#define SPMI_CHANNEL_OFFSET				0x0300
+#define SPMI_SLAVE_OFFSET				0x20
 
-#define SPMI_APB_SPMI_CMD_BASE_ADDR				0x0100
+#define SPMI_APB_SPMI_CMD_BASE_ADDR			0x0100
 
 #define SPMI_APB_SPMI_WDATA0_BASE_ADDR			0x0104
 #define SPMI_APB_SPMI_WDATA1_BASE_ADDR			0x0108
@@ -35,21 +35,21 @@
 #define SPMI_APB_SPMI_RDATA2_BASE_ADDR			0x020c
 #define SPMI_APB_SPMI_RDATA3_BASE_ADDR			0x0210
 
-#define SPMI_PER_DATAREG_BYTE					4
+#define SPMI_PER_DATAREG_BYTE				4
 /*
  * SPMI cmd register
  */
-#define SPMI_APB_SPMI_CMD_EN						BIT(31)
+#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
 
 #define bswap_32(X)   \
     ((((u32)(X) & 0xff000000) >> 24) | \
      (((u32)(X) & 0x00ff0000) >> 8) | \
      (((u32)(X) & 0x0000ff00) << 8) | \
      (((u32)(X) & 0x000000ff) << 24))
+#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET		16
+#define SPMI_APB_SPMI_CMD_ADDR_OFFSET			0
 
 /* Command Opcodes */
 
@@ -70,15 +70,15 @@ enum spmi_controller_cmd_op_code {
 /*
  * SPMI status register
  */
-#define SPMI_APB_TRANS_DONE						BIT(0)
-#define SPMI_APB_TRANS_FAIL						BIT(2)
+#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)
+#define SPMI_CONTROLLER_MAX_TRANS_BYTES		16
 
 /*
  * @base base address of the PMIC Arbiter core registers.
@@ -114,8 +114,10 @@ static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
 {
 	u32 status = 0;
 	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
-	u32 offset = SPMI_APB_SPMI_STATUS_BASE_ADDR + SPMI_CHANNEL_OFFSET * ctrl_dev->channel
-		+ SPMI_SLAVE_OFFSET * sid;
+	u32 offset;
+
+	offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
+	offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
 
 	while (timeout--) {
 		status = readl(base + offset);
-- 
2.26.2


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

* [PATCH 11/33] spmi: hisi-spmi-controller: use le32 macros where needed
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (9 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 10/33] spmi: hisi-spmi-controller: adjust whitespaces at defines Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 12/33] spmi: hisi-spmi-controller: add debug when values are read/write Mauro Carvalho Chehab
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

Instead of manually using bswap_32(), just use the
le32 macros.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 7fae267a6062..cacd28150b49 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/spmi.h>
-#include <linux/spmi.h>
 
 #define SPMI_CONTROLLER_NAME		"spmi_controller"
 
@@ -43,11 +42,6 @@
 #define SPMI_APB_SPMI_CMD_TYPE_OFFSET			24
 #define SPMI_APB_SPMI_CMD_LENGTH_OFFSET			20
 
-#define bswap_32(X)   \
-    ((((u32)(X) & 0xff000000) >> 24) | \
-     (((u32)(X) & 0x00ff0000) >> 8) | \
-     (((u32)(X) & 0x0000ff00) << 8) | \
-     (((u32)(X) & 0x000000ff) << 24))
 #define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET		16
 #define SPMI_APB_SPMI_CMD_ADDR_OFFSET			0
 
@@ -179,14 +173,15 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 
 	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
 
-	rc = spmi_controller_wait_for_done(spmi_controller, spmi_controller->base, sid, addr);
+	rc = spmi_controller_wait_for_done(spmi_controller,
+					   spmi_controller->base, sid, addr);
 	if (rc)
 		goto done;
 
 	i = 0;
 	do {
 		data = readl(spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET * sid + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i * SPMI_PER_DATAREG_BYTE);
-		data = bswap_32(data);
+		data = be32_to_cpu((__be32)data);
 		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
 			memcpy(buf, &data, sizeof(data));
 			buf += sizeof(data);
@@ -210,8 +205,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 {
 	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
 	unsigned long flags;
-	u32 cmd;
-	u32 data = 0;
+	u32 cmd, data;
 	int rc;
 	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
 	u8 op_code, i;
@@ -246,7 +240,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 
 	i = 0;
 	do {
-		memset(&data, 0, sizeof(data));
+		data = 0;
 		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
 			memcpy(&data, buf, sizeof(data));
 			buf += sizeof(data);
@@ -255,8 +249,8 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 			buf += (bc % SPMI_PER_DATAREG_BYTE);
 		}
 
-		data = bswap_32(data);
-		writel(data, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR + SPMI_PER_DATAREG_BYTE * i);
+		writel((u32)cpu_to_be32(data),
+		       spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR + SPMI_PER_DATAREG_BYTE * i);
 		i++;
 	} while (bc > i * SPMI_PER_DATAREG_BYTE);
 
-- 
2.26.2


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

* [PATCH 12/33] spmi: hisi-spmi-controller: add debug when values are read/write
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (10 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 11/33] spmi: hisi-spmi-controller: use le32 macros where needed Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 13/33] mfd, regulator: coding style fixups at the HiSilicon SPMI PMIC code Mauro Carvalho Chehab
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

It is interesting to be able to check if the driver is doing
the right thing. So, add some debug macros to allow checking it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index cacd28150b49..e996114bc717 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -41,7 +41,6 @@
 #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
 
@@ -135,10 +134,11 @@ static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
 }
 
 static int spmi_read_cmd(struct spmi_controller *ctrl,
-			 u8 opc, u8 sid, u16 addr, u8 *buf, size_t bc)
+			 u8 opc, u8 sid, u16 addr, u8 *__buf, size_t bc)
 {
 	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
 	unsigned long flags;
+	u8 *buf = __buf;
 	u32 cmd, data;
 	int rc;
 	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
@@ -197,13 +197,18 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 	if (rc)
 		dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
 			opc, sid, addr, bc + 1);
+	else
+		dev_dbg(spmi_controller->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
+			__func__, sid, addr, (int)bc, __buf);
+
 	return rc;
 }
 
 static int spmi_write_cmd(struct spmi_controller *ctrl,
-			  u8 opc, u8 sid, u16 addr, const u8 *buf, size_t bc)
+			  u8 opc, u8 sid, u16 addr, const u8 *__buf, size_t bc)
 {
 	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	const u8 *buf = __buf;
 	unsigned long flags;
 	u32 cmd, data;
 	int rc;
@@ -263,6 +268,9 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 	if (rc)
 		dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
 			opc, sid, addr, bc);
+	else
+		dev_dbg(spmi_controller->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
+			__func__, sid, addr, (int)bc, __buf);
 
 	return rc;
 }
@@ -275,6 +283,7 @@ static int spmi_controller_probe(struct platform_device *pdev)
 	int ret = 0;
 
 	dev_info(&pdev->dev, "HISI SPMI probe\n");
+
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
 	if (!ctrl) {
 		dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
-- 
2.26.2


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

* [PATCH 13/33] mfd, regulator: coding style fixups at the HiSilicon SPMI PMIC code
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (11 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 12/33] spmi: hisi-spmi-controller: add debug when values are read/write Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 14/33] spmi: add hisi-spmi-controller to the building system Mauro Carvalho Chehab
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Liam Girdwood, Mark Brown, linux-kernel

There are several issues on those drivers related to their
coding style. Solve most of them.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hisi_pmic_spmi.c            | 126 ++++++++++++------------
 drivers/regulator/hisi_regulator_spmi.c | 110 +++++++++++----------
 include/linux/mfd/hisi_pmic.h           |  18 +---
 3 files changed, 120 insertions(+), 134 deletions(-)

diff --git a/drivers/mfd/hisi_pmic_spmi.c b/drivers/mfd/hisi_pmic_spmi.c
index 0986e24ad304..be42fed16bd2 100644
--- a/drivers/mfd/hisi_pmic_spmi.c
+++ b/drivers/mfd/hisi_pmic_spmi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device driver for regulators in HISI PMIC IC
  *
@@ -76,7 +77,8 @@ u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
 		return 0;
 	}
 
-	ret = spmi_ext_register_readl(pdev, reg, (unsigned char*)&read_value, 1);/*lint !e734 !e732 */
+	ret = spmi_ext_register_readl(pdev, reg,
+				      (unsigned char *)&read_value, 1);
 	if (ret) {
 		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
 		return 0;
@@ -96,7 +98,7 @@ void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
 		return;
 	}
 
-	ret = spmi_ext_register_writel(pdev, reg, (unsigned char*)&val, 1);/*lint !e734 !e732 */
+	ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1);
 	if (ret) {
 		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
 		return;
@@ -126,14 +128,13 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	for (i = 0; i < pmic->irqarray; i++) {
 		pending = hisi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
 		pending &= HISI_MASK_FIELD;
-		if (pending != 0) {
-			pr_info("pending[%d]=0x%lx\n\r", i, pending);
-		}
+		if (pending != 0)
+			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
 
 		hisi_pmic_write(pmic, (i + pmic->irq_addr.start_addr), pending);
 
-		/*solve powerkey order*/
-		if ((HISI_IRQ_KEY_NUM == i) && ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
+		/* 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);
@@ -141,7 +142,7 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 
 		if (pending) {
 			for_each_set_bit(offset, &pending, HISI_BITS)
-				generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]);/*lint !e679 */
+				generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]);
 		}
 	}
 
@@ -150,16 +151,16 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 		for (i = 0; i < pmic->irqarray1; i++) {
 			pending = hisi_pmic_read(pmic, (i + pmic->irq_addr1.start_addr));
 			pending &= HISI_MASK_FIELD;
-			if (pending != 0) {
-				pr_info("pending[%d]=0x%lx\n\r", i, pending);
-			}
+			if (pending != 0)
+				pr_debug("pending[%d]=0x%lx\n\r", i, pending);
 
 			hisi_pmic_write(pmic, (i + pmic->irq_addr1.start_addr), pending);
 
-			if (pending) {
-				for_each_set_bit(offset, &pending, HISI_BITS)
-					generic_handle_irq(pmic->irqs[offset + (i+HISI_PMIC_FIRST_GROUP_INT_NUM) * HISI_BITS]);/*lint !e679 */
-			}
+			if (!pending)
+				continue;
+
+			for_each_set_bit(offset, &pending, HISI_BITS)
+				generic_handle_irq(pmic->irqs[offset + (i + HISI_PMIC_FIRST_GROUP_INT_NUM) * HISI_BITS]);
 		}
 	}
 
@@ -174,11 +175,16 @@ static void hisi_irq_mask(struct irq_data *d)
 
 	offset = (irqd_to_hwirq(d) >> 3);
 	if (pmic->g_extinterrupt_flag == 1) {
-		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
+		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM) {
 			offset += pmic->irq_mask_addr.start_addr;
-		else/*Change addr when irq num larger than 16 because interrupt addr is nonsequence*/
-			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
-	}else{
+		} else {
+			/*
+			 * Change addr when irq num larger than 16 because
+			 * interrupt addr is nonsequence
+			 */
+			offset = offset + (pmic->irq_mask_addr1.start_addr) - HISI_PMIC_FIRST_GROUP_INT_NUM;
+		}
+	} else {
 		offset += pmic->irq_mask_addr.start_addr;
 	}
 	spin_lock_irqsave(&pmic->lock, flags);
@@ -199,8 +205,8 @@ static void hisi_irq_unmask(struct irq_data *d)
 		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
 			offset += pmic->irq_mask_addr.start_addr;
 		else
-			offset = offset+(pmic->irq_mask_addr1.start_addr)-HISI_PMIC_FIRST_GROUP_INT_NUM;
-	}else{
+			offset = offset + (pmic->irq_mask_addr1.start_addr) - HISI_PMIC_FIRST_GROUP_INT_NUM;
+	} else {
 		offset += pmic->irq_mask_addr.start_addr;
 	}
 	spin_lock_irqsave(&pmic->lock, flags);
@@ -219,7 +225,7 @@ static struct irq_chip hisi_pmu_irqchip = {
 };
 
 static int hisi_irq_map(struct irq_domain *d, unsigned int virq,
-			  irq_hw_number_t hw)
+			irq_hw_number_t hw)
 {
 	struct hisi_pmic *pmic = d->host_data;
 
@@ -231,19 +237,18 @@ static int hisi_irq_map(struct irq_domain *d, unsigned int virq,
 	return 0;
 }
 
-static struct irq_domain_ops hisi_domain_ops = {
+static const struct irq_domain_ops hisi_domain_ops = {
 	.map	= hisi_irq_map,
 	.xlate	= irq_domain_xlate_twocell,
 };
 
-/*lint -e570 -e64*/
 static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *pmic)
 {
 	int ret = 0;
 
 	/*get pmic irq num*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num",
-						&(pmic->irqnum), 1);
+					 &pmic->irqnum, 1);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-num property set\n");
 		ret = -ENODEV;
@@ -252,7 +257,7 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 
 	/*get pmic irq array number*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array",
-						&(pmic->irqarray), 1);
+					 &pmic->irqarray, 1);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-array property set\n");
 		ret = -ENODEV;
@@ -261,7 +266,7 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 
 	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr",
-						(int *)&pmic->irq_mask_addr, 2);
+					 (int *)&pmic->irq_mask_addr, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-mask-addr property set\n");
 		ret = -ENODEV;
@@ -270,7 +275,7 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 
 	/*SOC_PMIC_IRQ0_ADDR*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr",
-						(int *)&pmic->irq_addr, 2);
+					 (int *)&pmic->irq_addr, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-addr property set\n");
 		ret = -ENODEV;
@@ -279,7 +284,7 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 
 	/*pmic lock*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-lock",
-						(int *)&pmic->normal_lock, 2);
+					 (int *)&pmic->normal_lock, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-lock property set\n");
 		ret = -ENODEV;
@@ -288,7 +293,7 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 
 	/*pmic debug lock*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-debug-lock",
-						(int *)&pmic->debug_lock, 2);
+					 (int *)&pmic->debug_lock, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-debug-lock property set\n");
 		ret = -ENODEV;
@@ -296,17 +301,15 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 	}
 
 	return ret;
-}/*lint -restore*/
+}
 
-
-/*lint -e570 -e64*/
 static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *pmic)
 {
 	int ret = 0;
 
 	/*get pmic irq num*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num1",
-						&(pmic->irqnum1), 1);
+					 &pmic->irqnum1, 1);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-num1 property set\n");
 		ret = -ENODEV;
@@ -316,7 +319,7 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 
 	/*get pmic irq array number*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array1",
-						&(pmic->irqarray1), 1);
+					 &pmic->irqarray1, 1);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-array1 property set\n");
 		ret = -ENODEV;
@@ -325,7 +328,7 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 
 	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr1",
-						(int *)&pmic->irq_mask_addr1, 2);
+					 (int *)&pmic->irq_mask_addr1, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-mask-addr1 property set\n");
 		ret = -ENODEV;
@@ -334,7 +337,7 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 
 	/*SOC_PMIC_IRQ0_ADDR*/
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr1",
-						(int *)&pmic->irq_addr1, 2);
+					 (int *)&pmic->irq_addr1, 2);
 	if (ret) {
 		pr_err("no hisilicon,hisi-pmic-irq-addr1 property set\n");
 		ret = -ENODEV;
@@ -343,21 +346,22 @@ static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *
 
 	pmic->g_extinterrupt_flag = 1;
 	return ret;
-}/*lint -restore*/
+}
 
 static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
 {
 	int i;
-	for (i = 0 ; i < pmic->irq_mask_addr.array; i++) {
+
+	for (i = 0 ; i < pmic->irq_mask_addr.array; i++)
 		hisi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i, HISI_MASK_STATE);
-	}
 
 	for (i = 0 ; i < pmic->irq_addr.array; i++) {
 		unsigned int pending = hisi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
-		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n", pmic->irq_addr.start_addr + i, pending);
+
+		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
+			 pmic->irq_addr.start_addr + i, pending);
 		hisi_pmic_write(pmic, pmic->irq_addr.start_addr + i, HISI_MASK_STATE);
 	}
-
 }
 
 static void hisi_pmic_irq1_prc(struct hisi_pmic *pmic)
@@ -371,7 +375,10 @@ static void hisi_pmic_irq1_prc(struct hisi_pmic *pmic)
 
 		for (i = 0 ; i < pmic->irq_addr1.array; i++) {
 			pending1 = hisi_pmic_read(pmic, pmic->irq_addr1.start_addr + i);
-			pr_debug("PMU IRQ address1 value:irq[0x%x] = 0x%x\n", pmic->irq_addr1.start_addr + i, pending1);
+
+			pr_debug("PMU IRQ address1 value:irq[0x%x] = 0x%x\n",
+				 pmic->irq_addr1.start_addr + i, pending1);
+
 			hisi_pmic_write(pmic, pmic->irq_addr1.start_addr + i, HISI_MASK_STATE);
 		}
 	}
@@ -389,23 +396,20 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	unsigned int virq;
 
 	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
-	if (!pmic) {
-		dev_err(dev, "cannot allocate hisi_pmic device info\n");
+	if (!pmic)
 		return -ENOMEM;
-	}
 
 	/*TODO: get pmic dts info*/
 	ret = get_pmic_device_tree_data(np, pmic);
 	if (ret) {
-		dev_err(&pdev->dev, "Error reading hisi pmic dts \n");
+		dev_err(&pdev->dev, "Error reading hisi pmic dts\n");
 		return ret;
 	}
 
 	/*get pmic dts the second group irq*/
 	ret = get_pmic_device_tree_data1(np, pmic);
-	if (ret) {
+	if (ret)
 		dev_err(&pdev->dev, "the platform don't support ext-interrupt.\n");
-	}
 
 	/* TODO: get and enable clk request */
 	spin_lock_init(&pmic->lock);
@@ -416,9 +420,8 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	if (ret)
 		pr_err("no hisilicon,pmic_fpga_flag property set\n");
 
-	if (PMIC_FPGA_FLAG == fpga_flag) {
+	if (fpga_flag == PMIC_FPGA_FLAG)
 		goto after_irq_register;
-	}
 
 	pmic->gpio = of_get_gpio_flags(np, 0, &flags);
 	if (pmic->gpio < 0)
@@ -442,12 +445,9 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 
 	pmic->irqnum += pmic->irqnum1;
 
-	pmic->irqs = (unsigned int *)devm_kmalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
-	if (!pmic->irqs) {
-		pr_err("%s:Failed to alloc memory for pmic irq number!\n", __func__);
+	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
+	if (!pmic->irqs)
 		goto irq_malloc;
-	}
-	memset(pmic->irqs, 0, pmic->irqnum);
 
 	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
 					     &hisi_domain_ops, pmic);
@@ -469,7 +469,7 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	}
 
 	ret = request_threaded_irq(pmic->irq, hisi_irq_handler, NULL,
-				IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+				   IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
 				   "pmic", pmic);
 	if (ret < 0) {
 		dev_err(dev, "could not claim pmic %d\n", ret);
@@ -480,7 +480,6 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 after_irq_register:
 	return 0;
 
-
 request_theaded_irq:
 irq_create_mapping:
 irq_domain:
@@ -491,19 +490,18 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 
 static void hisi_pmic_remove(struct spmi_device *pdev)
 {
-
 	struct hisi_pmic *pmic = dev_get_drvdata(&pdev->dev);
 
 	free_irq(pmic->irq, pmic);
 	gpio_free(pmic->gpio);
 	devm_kfree(&pdev->dev, pmic);
-
 }
+
 static int hisi_pmic_suspend(struct device *dev, pm_message_t state)
 {
 	struct hisi_pmic *pmic = dev_get_drvdata(dev);
 
-	if (NULL == pmic) {
+	if (!pmic) {
 		pr_err("%s:pmic is NULL\n", __func__);
 		return -ENOMEM;
 	}
@@ -512,13 +510,13 @@ static int hisi_pmic_suspend(struct device *dev, pm_message_t state)
 	pr_info("%s:-\n", __func__);
 
 	return 0;
-}/*lint !e715 */
+}
 
 static int hisi_pmic_resume(struct device *dev)
 {
 	struct hisi_pmic *pmic = dev_get_drvdata(dev);
 
-	if (NULL == pmic) {
+	if (!pmic) {
 		pr_err("%s:pmic is NULL\n", __func__);
 		return -ENOMEM;
 	}
@@ -552,10 +550,8 @@ static void __exit hisi_pmic_exit(void)
 	spmi_driver_unregister(&hisi_pmic_driver);
 }
 
-
 subsys_initcall_sync(hisi_pmic_init);
 module_exit(hisi_pmic_exit);
 
 MODULE_DESCRIPTION("PMIC driver");
 MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/regulator/hisi_regulator_spmi.c b/drivers/regulator/hisi_regulator_spmi.c
index 904cb64b1dcd..5f6e4ba4b99e 100644
--- a/drivers/regulator/hisi_regulator_spmi.c
+++ b/drivers/regulator/hisi_regulator_spmi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device driver for regulators in Hisi IC
  *
@@ -52,7 +53,7 @@ struct hisi_regulator {
 	u32 off_on_delay;
 	u32 eco_uA;
 	struct regulator_desc rdesc;
-	int (*dt_parse)(struct hisi_regulator *, struct spmi_device *);
+	int (*dt_parse)(struct hisi_regulator *reg, struct spmi_device *spmi);
 };
 
 static DEFINE_MUTEX(enable_mutex);
@@ -77,8 +78,9 @@ static int hisi_regulator_is_enabled(struct regulator_dev *dev)
 	struct hisi_pmic *pmic = rdev_to_pmic(dev);
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	pr_debug("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n", __func__, sreg->register_info.ctrl_reg,\
-			(reg_val & sreg->register_info.enable_mask));
+	pr_debug("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n",
+		 __func__, sreg->register_info.ctrl_reg,
+		(reg_val & sreg->register_info.enable_mask));
 
 	return ((reg_val & sreg->register_info.enable_mask) != 0);
 }
@@ -98,14 +100,13 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 	usleep_range(HISI_REGS_ENA_PROTECT_TIME,
 		     HISI_REGS_ENA_PROTECT_TIME + 1000);
 
-
-
 	/* set enable register */
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
-				sreg->register_info.enable_mask,
+		      sreg->register_info.enable_mask,
 				sreg->register_info.enable_mask);
-	pr_debug("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n", __func__, sreg->register_info.ctrl_reg,\
-			sreg->register_info.enable_mask);
+	pr_debug("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n",
+		 __func__, sreg->register_info.ctrl_reg,
+		 sreg->register_info.enable_mask);
 
 	mutex_unlock(&enable_mutex);
 
@@ -119,7 +120,7 @@ static int hisi_regulator_disable(struct regulator_dev *dev)
 
 	/* set enable register to 0 */
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
-				sreg->register_info.enable_mask, 0);
+		      sreg->register_info.enable_mask, 0);
 
 	return 0;
 }
@@ -132,7 +133,8 @@ static int hisi_regulator_get_voltage(struct regulator_dev *dev)
 
 	/* get voltage selector */
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.vset_reg);
-	pr_debug("<[%s]: vset_reg=0x%x>\n", __func__, sreg->register_info.vset_reg);
+	pr_debug("<[%s]: vset_reg=0x%x>\n",
+		 __func__, sreg->register_info.vset_reg);
 
 	selector = (reg_val & sreg->register_info.vset_mask) >>
 				(ffs(sreg->register_info.vset_mask) - 1);
@@ -141,7 +143,7 @@ static int hisi_regulator_get_voltage(struct regulator_dev *dev)
 }
 
 static int hisi_regulator_set_voltage(struct regulator_dev *dev,
-				int min_uV, int max_uV, unsigned *selector)
+				      int min_uV, int max_uV, unsigned int *selector)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
 	struct hisi_pmic *pmic = rdev_to_pmic(dev);
@@ -162,14 +164,14 @@ static int hisi_regulator_set_voltage(struct regulator_dev *dev,
 	*selector = vsel;
 	/* set voltage selector */
 	hisi_pmic_rmw(pmic, sreg->register_info.vset_reg,
-		sreg->register_info.vset_mask,
+		      sreg->register_info.vset_mask,
 		vsel << (ffs(sreg->register_info.vset_mask) - 1));
 
-	pr_debug("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n", __func__,\
-			sreg->register_info.vset_reg,\
-			sreg->register_info.vset_mask,\
-			vsel << (ffs(sreg->register_info.vset_mask) - 1)\
-			);
+	pr_debug("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n",
+		 __func__,
+		 sreg->register_info.vset_reg,
+		 sreg->register_info.vset_mask,
+		 vsel << (ffs(sreg->register_info.vset_mask) - 1));
 
 	return ret;
 }
@@ -181,10 +183,10 @@ static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
 	u32 reg_val;
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	pr_debug("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n", __func__, reg_val,\
-			sreg->register_info.ctrl_reg,\
-			sreg->register_info.eco_mode_mask\
-		   );
+	pr_debug("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n",
+		 __func__, reg_val,
+		sreg->register_info.ctrl_reg,
+		sreg->register_info.eco_mode_mask);
 
 	if (reg_val & sreg->register_info.eco_mode_mask)
 		return REGULATOR_MODE_IDLE;
@@ -193,7 +195,7 @@ static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
 }
 
 static int hisi_regulator_set_mode(struct regulator_dev *dev,
-						unsigned int mode)
+				   unsigned int mode)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
 	struct hisi_pmic *pmic = rdev_to_pmic(dev);
@@ -212,31 +214,31 @@ static int hisi_regulator_set_mode(struct regulator_dev *dev,
 
 	/* set mode */
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
+		      sreg->register_info.eco_mode_mask,
+		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
+
+	pr_debug("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n",
+		 __func__,
+		sreg->register_info.ctrl_reg,
 		sreg->register_info.eco_mode_mask,
 		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
-
-	pr_debug("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n", __func__,\
-			sreg->register_info.ctrl_reg,\
-			sreg->register_info.eco_mode_mask,\
-			eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1)\
-		   );
 	return 0;
 }
 
-
-unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
-			int input_uV, int output_uV, int load_uA)
+static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
+						    int input_uV, int output_uV,
+						    int load_uA)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
 
-	if ((load_uA == 0) || ((unsigned int)load_uA > sreg->eco_uA))
+	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA))
 		return REGULATOR_MODE_NORMAL;
 	else
 		return REGULATOR_MODE_IDLE;
 }
 
 static int hisi_dt_parse_common(struct hisi_regulator *sreg,
-					struct spmi_device *pdev)
+				struct spmi_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -246,7 +248,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 
 	/* parse .register_info.ctrl_reg */
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-ctrl",
-						register_info, 3);
+					 register_info, 3);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-ctrl property set\n");
 		goto dt_parse_common_end;
@@ -257,7 +259,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 
 	/* parse .register_info.vset_reg */
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset",
-						register_info, 2);
+					 register_info, 2);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-vset property set\n");
 		goto dt_parse_common_end;
@@ -267,7 +269,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 
 	/* parse .off-on-delay */
 	ret = of_property_read_u32(np, "hisilicon,hisi-off-on-delay-us",
-						&sreg->off_on_delay);
+				   &sreg->off_on_delay);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-off-on-delay-us property set\n");
 		goto dt_parse_common_end;
@@ -294,7 +296,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 }
 
 static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
-				struct spmi_device *pdev)
+			     struct spmi_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -312,7 +314,7 @@ static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
 
 	/* alloc space for .volt_table */
 	v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
-								GFP_KERNEL);
+			       GFP_KERNEL);
 	if (unlikely(!v_table)) {
 		ret = -ENOMEM;
 		dev_err(dev, "no memory for .volt_table\n");
@@ -320,7 +322,7 @@ static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
 	}
 
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset-table",
-						v_table, rdesc->n_voltages);
+					 v_table, rdesc->n_voltages);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-vset-table property set\n");
 		goto dt_parse_ldo_end1;
@@ -362,7 +364,7 @@ static const struct hisi_regulator hisi_regulator_ldo = {
 	.dt_parse = hisi_dt_parse_ldo,
 };
 
-static struct of_device_id of_hisi_regulator_match_tbl[] = {
+static const struct of_device_id of_hisi_regulator_match_tbl[] = {
 	{
 		.compatible = "hisilicon-hisi-ldo",
 		.data = &hisi_regulator_ldo,
@@ -388,14 +390,14 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	int ret = 0;
 	/* to check which type of regulator this is */
 	match = of_match_device(of_hisi_regulator_match_tbl, &pdev->dev);
-	if (NULL == match) {
+	if (!match) {
 		pr_err("get hisi regulator fail!\n\r");
 		return -EINVAL;
 	}
 
 	template = match->data;
 	initdata = of_get_regulator_init_data(dev, np, NULL);
-	if (NULL == initdata) {
+	if (!initdata) {
 		pr_err("get regulator init data error !\n");
 		return -EINVAL;
 	}
@@ -404,14 +406,14 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	constraint = &initdata->constraints;
 
 	ret = of_property_read_u32_array(np, "hisilicon,valid-modes-mask",
-						&(constraint->valid_modes_mask), 1);
+					 &constraint->valid_modes_mask, 1);
 	if (ret) {
 		pr_err("no hisilicon,valid-modes-mask property set\n");
 		ret = -ENODEV;
 		return ret;
 	}
 	ret = of_property_read_u32_array(np, "hisilicon,valid-idle-mask",
-						&temp_modes, 1);
+					 &temp_modes, 1);
 	if (ret) {
 		pr_err("no hisilicon,valid-modes-mask property set\n");
 		ret = -ENODEV;
@@ -420,18 +422,16 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	constraint->valid_ops_mask |= temp_modes;
 
 	sreg = kmemdup(template, sizeof(*sreg), GFP_KERNEL);
-	if (!sreg) {
-		pr_err("template kememdup is fail. \n");
+	if (!sreg)
 		return -ENOMEM;
-	}
+
 	sreg->name = initdata->constraints.name;
 	rdesc = &sreg->rdesc;
 	rdesc->name = sreg->name;
 	rdesc->min_uV = initdata->constraints.min_uV;
 	supplyname = of_get_property(np, "hisilicon,supply_name", NULL);
-	if (supplyname != NULL) {
+	if (supplyname)
 		initdata->supply_regulator = supplyname;
-	}
 
 	/* to parse device tree data for regulator specific */
 	ret = sreg->dt_parse(sreg, pdev);
@@ -454,8 +454,9 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 		goto hisi_probe_end;
 	}
 
-	pr_debug("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n", rdesc->name,\
-			constraint->valid_modes_mask, constraint->valid_ops_mask);
+	pr_debug("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n",
+		 rdesc->name,
+		 constraint->valid_modes_mask, constraint->valid_ops_mask);
 
 	dev_set_drvdata(dev, rdev);
 hisi_probe_end:
@@ -477,11 +478,12 @@ static void hisi_regulator_remove(struct spmi_device *pdev)
 
 	kfree(sreg);
 }
+
 static int hisi_regulator_suspend(struct device *dev, pm_message_t state)
 {
 	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
 
-	if (NULL == hisi_regulator) {
+	if (!hisi_regulator) {
 		pr_err("%s:regulator is NULL\n", __func__);
 		return -ENOMEM;
 	}
@@ -490,13 +492,13 @@ static int hisi_regulator_suspend(struct device *dev, pm_message_t state)
 	pr_info("%s:-\n", __func__);
 
 	return 0;
-}/*lint !e715 */
+}
 
 static int hisi_regulator_resume(struct device *dev)
 {
 	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
 
-	if (NULL == hisi_regulator) {
+	if (!hisi_regulator) {
 		pr_err("%s:regulator is NULL\n", __func__);
 		return -ENOMEM;
 	}
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hisi_pmic.h
index b387575fb43c..1f986dd5f31c 100644
--- a/include/linux/mfd/hisi_pmic.h
+++ b/include/linux/mfd/hisi_pmic.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Header file for device driver Hi6421 PMIC
  *
@@ -5,19 +6,6 @@
  * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #ifndef	__HISI_PMIC_H
@@ -25,12 +13,12 @@
 
 #include <linux/irqdomain.h>
 
-#define HISI_REGS_ENA_PROTECT_TIME	(0) 	/* in microseconds */
+#define HISI_REGS_ENA_PROTECT_TIME	(0)	/* in microseconds */
 #define HISI_ECO_MODE_ENABLE		(1)
 #define HISI_ECO_MODE_DISABLE		(0)
 
 typedef int (*pmic_ocp_callback)(char *);
-extern int hisi_pmic_special_ocp_register(char *power_name, pmic_ocp_callback handler);
+int hisi_pmic_special_ocp_register(char *power_name, pmic_ocp_callback handler);
 
 struct irq_mask_info {
 	int start_addr;
-- 
2.26.2


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

* [PATCH 14/33] spmi: add hisi-spmi-controller to the building system
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (12 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 13/33] mfd, regulator: coding style fixups at the HiSilicon SPMI PMIC code Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 20:53   ` kernel test robot
  2020-08-11 15:41 ` [PATCH 15/33] mfd: Kconfig: fix a typo Mauro Carvalho Chehab
                   ` (20 subsequent siblings)
  34 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	linux-arm-msm, linux-kernel

Now that the driver was ported to upstream, add it as a
SPMI controller.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/Kconfig  | 9 +++++++++
 drivers/spmi/Makefile | 2 ++
 2 files changed, 11 insertions(+)

diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index a53bad541f1a..b44e2ab6bf81 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -25,4 +25,13 @@ config SPMI_MSM_PMIC_ARB
 	  This is required for communicating with Qualcomm PMICs and
 	  other devices that have the SPMI interface.
 
+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.
+
 endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 55a94cadeffe..694853e391cb 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -5,3 +5,5 @@
 obj-$(CONFIG_SPMI)	+= spmi.o
 
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
+
+obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
-- 
2.26.2


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

* [PATCH 15/33] mfd: Kconfig: fix a typo
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (13 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 14/33] spmi: add hisi-spmi-controller to the building system Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 16/33] spmi: hisi-spmi-controller: fix the dev_foo() logic Mauro Carvalho Chehab
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones, linux-kernel

individul -> individual

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a37d7d171382..e42d11849947 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -493,7 +493,7 @@ config MFD_HI6421_PMIC
 	  Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi-
 	  functions, such as regulators, RTC, codec, Coulomb counter, etc.
 	  This driver includes core APIs _only_. You have to select
-	  individul components like voltage regulators under corresponding
+	  individual components like voltage regulators under corresponding
 	  menus in order to enable them.
 	  We communicate with the Hi6421 via memory-mapped I/O.
 
-- 
2.26.2


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

* [PATCH 16/33] spmi: hisi-spmi-controller: fix the dev_foo() logic
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (14 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 15/33] mfd: Kconfig: fix a typo Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 17/33] mfd: pmic: add drivers for hi6421v600 Mauro Carvalho Chehab
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Stephen Boyd,
	Mayulong, linux-arm-msm, linux-kernel

Right now, driver is printing some messages as:

	[   33.833026] (NULL device *): spmi_read_cmd: id:0 addr:0x17, read value: 00

This is because dev_foo() are not using a device with a name
set. Change the logic for it to print it right.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/spmi/hisi-spmi-controller.c | 41 +++++++++++++++--------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index e996114bc717..153bcdb0cde4 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -102,7 +102,8 @@ struct spmi_controller_dev {
 	u32			channel;
 };
 
-static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
+static int spmi_controller_wait_for_done(struct device *dev,
+					 struct spmi_controller_dev *ctrl_dev,
 					 void __iomem *base, u8 sid, u16 addr)
 {
 	u32 status = 0;
@@ -117,19 +118,17 @@ static int spmi_controller_wait_for_done(struct spmi_controller_dev *ctrl_dev,
 
 		if (status & SPMI_APB_TRANS_DONE) {
 			if (status & SPMI_APB_TRANS_FAIL) {
-				dev_err(ctrl_dev->dev,
-					"%s: transaction failed (0x%x)\n",
+				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);
 	}
 
-	dev_err(ctrl_dev->dev,
-		"%s: timeout, status 0x%x\n",
-		__func__, status);
+	dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
 	return -ETIMEDOUT;
 }
 
@@ -145,9 +144,9 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 	u8 op_code, i;
 
 	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-		dev_err(spmi_controller->dev
-		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
-					, SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
 		return  -EINVAL;
 	}
 
@@ -159,7 +158,7 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 	} else if (opc == SPMI_CMD_EXT_READL) {
 		op_code = SPMI_CMD_EXT_REG_READ_L;
 	} else {
-		dev_err(spmi_controller->dev, "invalid read cmd 0x%x", opc);
+		dev_err(&ctrl->dev, "invalid read cmd 0x%x", opc);
 		return -EINVAL;
 	}
 
@@ -173,7 +172,7 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 
 	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
 
-	rc = spmi_controller_wait_for_done(spmi_controller,
+	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
 					   spmi_controller->base, sid, addr);
 	if (rc)
 		goto done;
@@ -195,10 +194,11 @@ static int spmi_read_cmd(struct spmi_controller *ctrl,
 done:
 	spin_unlock_irqrestore(&spmi_controller->lock, flags);
 	if (rc)
-		dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
+		dev_err(&ctrl->dev,
+			"spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
 			opc, sid, addr, bc + 1);
 	else
-		dev_dbg(spmi_controller->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
+		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
 			__func__, sid, addr, (int)bc, __buf);
 
 	return rc;
@@ -216,9 +216,9 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 	u8 op_code, i;
 
 	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-		dev_err(spmi_controller->dev
-		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
-					, SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
 		return  -EINVAL;
 	}
 
@@ -230,7 +230,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 	} else if (opc == SPMI_CMD_EXT_WRITEL) {
 		op_code = SPMI_CMD_EXT_REG_WRITE_L;
 	} else {
-		dev_err(spmi_controller->dev, "invalid write cmd 0x%x", opc);
+		dev_err(&ctrl->dev, "invalid write cmd 0x%x", opc);
 		return -EINVAL;
 	}
 
@@ -262,14 +262,15 @@ static int spmi_write_cmd(struct spmi_controller *ctrl,
 	/* Start the transaction */
 	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
 
-	rc = spmi_controller_wait_for_done(spmi_controller, spmi_controller->base, sid, addr);
+	rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+					   spmi_controller->base, sid, addr);
 	spin_unlock_irqrestore(&spmi_controller->lock, flags);
 
 	if (rc)
-		dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
+		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
 			opc, sid, addr, bc);
 	else
-		dev_dbg(spmi_controller->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
+		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
 			__func__, sid, addr, (int)bc, __buf);
 
 	return rc;
-- 
2.26.2


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

* [PATCH 17/33] mfd: pmic: add drivers for hi6421v600
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (15 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 16/33] spmi: hisi-spmi-controller: fix the dev_foo() logic Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 18/33] mfd: hi6421-spmi-pmic: get rid of unused OF properties Mauro Carvalho Chehab
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Liam Girdwood, Mark Brown, linux-kernel

Rename the code to better match other upstream drivers,
and change the binding logic to ensure that the PMIC SPMI
driver will run before the regulator code.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/Kconfig                           |  15 ++
 drivers/mfd/Makefile                          |   1 +
 .../{hisi_pmic_spmi.c => hi6421-spmi-pmic.c}  |  84 +++-----
 drivers/regulator/Kconfig                     |   8 +
 drivers/regulator/Makefile                    |   1 +
 ...egulator_spmi.c => hi6421v600-regulator.c} | 186 +++++++++---------
 .../mfd/{hisi_pmic.h => hi6421-spmi-pmic.h}   |   0
 7 files changed, 145 insertions(+), 150 deletions(-)
 rename drivers/mfd/{hisi_pmic_spmi.c => hi6421-spmi-pmic.c} (91%)
 rename drivers/regulator/{hisi_regulator_spmi.c => hi6421v600-regulator.c} (80%)
 rename include/linux/mfd/{hisi_pmic.h => hi6421-spmi-pmic.h} (100%)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index e42d11849947..04c249649532 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -497,6 +497,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
+	select MFD_CORE
+	select REGMAP_MMIO
+	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 9367a92f795a..2ac0727dafc9 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/hisi_pmic_spmi.c b/drivers/mfd/hi6421-spmi-pmic.c
similarity index 91%
rename from drivers/mfd/hisi_pmic_spmi.c
rename to drivers/mfd/hi6421-spmi-pmic.c
index be42fed16bd2..939f7bd5d8ba 100644
--- a/drivers/mfd/hisi_pmic_spmi.c
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -24,13 +24,14 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/mfd/core.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
-#include <linux/mfd/hisi_pmic.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
 #include <linux/irq.h>
 #include <linux/spmi.h>
 #ifndef NO_IRQ
@@ -53,11 +54,8 @@
 /*define the first group interrupt register number*/
 #define HISI_PMIC_FIRST_GROUP_INT_NUM        2
 
-static const struct of_device_id of_hisi_pmic_match_tbl[] = {
-	{
-		.compatible = "hisilicon-hisi-pmic-spmi",
-	},
-	{ /* end */ }
+static const struct mfd_cell hi6421v600_devs[] = {
+	{ .name = "hi6421v600-regulator", },
 };
 
 /*
@@ -477,6 +475,22 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 		goto request_theaded_irq;
 	}
 
+	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 childs 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) {
+		dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
+		return ret;
+	}
+
 after_irq_register:
 	return 0;
 
@@ -497,61 +511,21 @@ static void hisi_pmic_remove(struct spmi_device *pdev)
 	devm_kfree(&pdev->dev, pmic);
 }
 
-static int hisi_pmic_suspend(struct device *dev, pm_message_t state)
-{
-	struct hisi_pmic *pmic = dev_get_drvdata(dev);
+static const struct of_device_id pmic_spmi_id_table[] = {
+	{ .compatible = "hisilicon,hi6421-spmi-pmic" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
 
-	if (!pmic) {
-		pr_err("%s:pmic is NULL\n", __func__);
-		return -ENOMEM;
-	}
-
-	pr_info("%s:+\n", __func__);
-	pr_info("%s:-\n", __func__);
-
-	return 0;
-}
-
-static int hisi_pmic_resume(struct device *dev)
-{
-	struct hisi_pmic *pmic = dev_get_drvdata(dev);
-
-	if (!pmic) {
-		pr_err("%s:pmic is NULL\n", __func__);
-		return -ENOMEM;
-	}
-
-	pr_info("%s:+\n", __func__);
-	pr_info("%s:-\n", __func__);
-
-	return 0;
-}
-
-MODULE_DEVICE_TABLE(spmi, pmic_spmi_id);
 static struct spmi_driver hisi_pmic_driver = {
 	.driver = {
-		.name	= "hisi_pmic",
-		.owner  = THIS_MODULE,
-		.of_match_table = of_hisi_pmic_match_tbl,
-		.suspend = hisi_pmic_suspend,
-		.resume = hisi_pmic_resume,
+		.name	= "hi6421-spmi-pmic",
+		.of_match_table = pmic_spmi_id_table,
 	},
 	.probe	= hisi_pmic_probe,
 	.remove	= hisi_pmic_remove,
 };
+module_spmi_driver(hisi_pmic_driver);
 
-static int __init hisi_pmic_init(void)
-{
-	return spmi_driver_register(&hisi_pmic_driver);
-}
-
-static void __exit hisi_pmic_exit(void)
-{
-	spmi_driver_unregister(&hisi_pmic_driver);
-}
-
-subsys_initcall_sync(hisi_pmic_init);
-module_exit(hisi_pmic_exit);
-
-MODULE_DESCRIPTION("PMIC driver");
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index edb1c4f8b496..de8a78487bb9 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -356,6 +356,14 @@ config REGULATOR_HI6421V530
 	  provides 5 general purpose LDOs, and all of them come with support
 	  to either ECO (idle) or sleep mode.
 
+config REGULATOR_HI6421V600
+	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
+	depends on MFD_HI6421_PMIC && OF
+	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_HI655X
 	tristate "Hisilicon HI655X PMIC regulators support"
 	depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0796e4a47afa..f59d5e3b5fd4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.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/hisi_regulator_spmi.c b/drivers/regulator/hi6421v600-regulator.c
similarity index 80%
rename from drivers/regulator/hisi_regulator_spmi.c
rename to drivers/regulator/hi6421v600-regulator.c
index 5f6e4ba4b99e..9aaafcbb1a36 100644
--- a/drivers/regulator/hisi_regulator_spmi.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -31,7 +31,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
-#include <linux/mfd/hisi_pmic.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/version.h>
@@ -53,20 +53,11 @@ struct hisi_regulator {
 	u32 off_on_delay;
 	u32 eco_uA;
 	struct regulator_desc rdesc;
-	int (*dt_parse)(struct hisi_regulator *reg, struct spmi_device *spmi);
+	struct hisi_pmic *pmic;
 };
 
 static DEFINE_MUTEX(enable_mutex);
 
-static inline struct hisi_pmic *rdev_to_pmic(struct regulator_dev *dev)
-{
-	/* regulator_dev parent to->
-	 * hisi regulator platform device_dev parent to->
-	 * hisi pmic platform device_dev
-	 */
-	return dev_get_drvdata(rdev_get_dev(dev)->parent->parent);
-}
-
 /* helper function to ensure when it returns it is at least 'delay_us'
  * microseconds after 'since'.
  */
@@ -75,7 +66,7 @@ static int hisi_regulator_is_enabled(struct regulator_dev *dev)
 {
 	u32 reg_val;
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
 	pr_debug("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n",
@@ -88,7 +79,7 @@ static int hisi_regulator_is_enabled(struct regulator_dev *dev)
 static int hisi_regulator_enable(struct regulator_dev *dev)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 
 	/* keep a distance of off_on_delay from last time disabled */
 	usleep_range(sreg->off_on_delay, sreg->off_on_delay + 1000);
@@ -116,7 +107,7 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 static int hisi_regulator_disable(struct regulator_dev *dev)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 
 	/* set enable register to 0 */
 	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
@@ -128,7 +119,7 @@ static int hisi_regulator_disable(struct regulator_dev *dev)
 static int hisi_regulator_get_voltage(struct regulator_dev *dev)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val, selector;
 
 	/* get voltage selector */
@@ -146,7 +137,7 @@ static int hisi_regulator_set_voltage(struct regulator_dev *dev,
 				      int min_uV, int max_uV, unsigned int *selector)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 	u32 vsel;
 	int ret = 0;
 
@@ -179,7 +170,7 @@ static int hisi_regulator_set_voltage(struct regulator_dev *dev,
 static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val;
 
 	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
@@ -198,7 +189,7 @@ static int hisi_regulator_set_mode(struct regulator_dev *dev,
 				   unsigned int mode)
 {
 	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
-	struct hisi_pmic *pmic = rdev_to_pmic(dev);
+	struct hisi_pmic *pmic = sreg->pmic;
 	u32 eco_mode;
 
 	switch (mode) {
@@ -238,7 +229,7 @@ static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
 }
 
 static int hisi_dt_parse_common(struct hisi_regulator *sreg,
-				struct spmi_device *pdev)
+				struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -296,7 +287,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 }
 
 static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
-			     struct spmi_device *pdev)
+			     struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
@@ -355,47 +346,32 @@ static struct regulator_ops hisi_ldo_rops = {
 	.get_optimum_mode = hisi_regulator_get_optimum_mode,
 };
 
-static const struct hisi_regulator hisi_regulator_ldo = {
-	.rdesc = {
-	.ops = &hisi_ldo_rops,
-		.type = REGULATOR_VOLTAGE,
-		.owner = THIS_MODULE,
-		},
-	.dt_parse = hisi_dt_parse_ldo,
-};
+/*
+ * Used only for parsing the DT properties
+ */
 
-static const struct of_device_id of_hisi_regulator_match_tbl[] = {
+static const struct of_device_id of_hisi_pmic_match_tbl[] = {
 	{
-		.compatible = "hisilicon-hisi-ldo",
-		.data = &hisi_regulator_ldo,
+		.compatible = "hisilicon,hi6421-spmi-pmic-ldo",
 	},
-	{ /* end */ }
+	{ }
 };
 
-static int hisi_regulator_probe(struct spmi_device *pdev)
+static int hisi_regulator_probe_ldo(struct platform_device *pdev,
+				    struct device_node *np,
+				    struct hisi_pmic *pmic)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
 	struct regulator_desc *rdesc;
 	struct regulator_dev *rdev;
 	struct hisi_regulator *sreg = NULL;
 	struct regulator_init_data *initdata;
 	struct regulator_config config = { };
-	const struct of_device_id *match;
 	struct regulation_constraints *constraint;
 	const char *supplyname = NULL;
 	unsigned int temp_modes;
-
-	const struct hisi_regulator *template = NULL;
 	int ret = 0;
-	/* to check which type of regulator this is */
-	match = of_match_device(of_hisi_regulator_match_tbl, &pdev->dev);
-	if (!match) {
-		pr_err("get hisi regulator fail!\n\r");
-		return -EINVAL;
-	}
 
-	template = match->data;
 	initdata = of_get_regulator_init_data(dev, np, NULL);
 	if (!initdata) {
 		pr_err("get regulator init data error !\n");
@@ -421,20 +397,25 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	}
 	constraint->valid_ops_mask |= temp_modes;
 
-	sreg = kmemdup(template, sizeof(*sreg), GFP_KERNEL);
+	sreg = kzalloc(sizeof(*sreg), GFP_KERNEL);
 	if (!sreg)
 		return -ENOMEM;
 
 	sreg->name = initdata->constraints.name;
+	sreg->pmic = pmic;
 	rdesc = &sreg->rdesc;
+
 	rdesc->name = sreg->name;
+	rdesc->ops = &hisi_ldo_rops;
+	rdesc->type = REGULATOR_VOLTAGE;
 	rdesc->min_uV = initdata->constraints.min_uV;
+
 	supplyname = of_get_property(np, "hisilicon,supply_name", NULL);
 	if (supplyname)
 		initdata->supply_regulator = supplyname;
 
-	/* to parse device tree data for regulator specific */
-	ret = sreg->dt_parse(sreg, pdev);
+	/* parse device tree data for regulator specific */
+	ret = hisi_dt_parse_ldo(sreg, pdev);
 	if (ret) {
 		dev_err(dev, "device tree parameter parse error!\n");
 		goto hisi_probe_end;
@@ -465,7 +446,59 @@ static int hisi_regulator_probe(struct spmi_device *pdev)
 	return ret;
 }
 
-static void hisi_regulator_remove(struct spmi_device *pdev)
+
+static int hisi_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 hisi_pmic *pmic;
+	int ret;
+
+	dev_dbg(&pdev->dev, "probing hi6421v600 regulator\n");
+	/*
+	 * 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 = hisi_regulator_probe_ldo(new_pdev, child, pmic);
+		if (ret < 0)
+			platform_device_put(new_pdev);
+	}
+
+	of_node_put(regulators);
+
+	return 0;
+}
+
+static int hisi_regulator_remove(struct platform_device *pdev)
 {
 	struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev);
 	struct hisi_regulator *sreg = rdev_get_drvdata(rdev);
@@ -477,63 +510,26 @@ static void hisi_regulator_remove(struct spmi_device *pdev)
 		devm_kfree(&pdev->dev, (unsigned int *)sreg->rdesc.volt_table);
 
 	kfree(sreg);
-}
-
-static int hisi_regulator_suspend(struct device *dev, pm_message_t state)
-{
-	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
-
-	if (!hisi_regulator) {
-		pr_err("%s:regulator is NULL\n", __func__);
-		return -ENOMEM;
-	}
-
-	pr_info("%s:+\n", __func__);
-	pr_info("%s:-\n", __func__);
 
 	return 0;
 }
 
-static int hisi_regulator_resume(struct device *dev)
-{
-	struct hisi_regulator *hisi_regulator = dev_get_drvdata(dev);
-
-	if (!hisi_regulator) {
-		pr_err("%s:regulator is NULL\n", __func__);
-		return -ENOMEM;
-	}
-
-	pr_info("%s:+\n", __func__);
-	pr_info("%s:-\n", __func__);
-
-	return 0;
-}
+static const struct platform_device_id hi6421v600_regulator_table[] = {
+	{ .name = "hi6421v600-regulator" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, hi6421v600_regulator_table);
 
-static struct spmi_driver hisi_pmic_driver = {
+static struct platform_driver hi6421v600_regulator_driver = {
+	.id_table = hi6421v600_regulator_table,
 	.driver = {
-		.name	= "hisi_regulator",
-		.owner  = THIS_MODULE,
-		.of_match_table = of_hisi_regulator_match_tbl,
-		.suspend = hisi_regulator_suspend,
-		.resume = hisi_regulator_resume,
+		.name	= "hi6421v600-regulator",
 	},
 	.probe	= hisi_regulator_probe,
 	.remove	= hisi_regulator_remove,
 };
+module_platform_driver(hi6421v600_regulator_driver);
 
-static int __init hisi_regulator_init(void)
-{
-	return spmi_driver_register(&hisi_pmic_driver);
-}
-
-static void __exit hisi_regulator_exit(void)
-{
-	spmi_driver_unregister(&hisi_pmic_driver);
-}
-
-fs_initcall(hisi_regulator_init);
-module_exit(hisi_regulator_exit);
-
-MODULE_DESCRIPTION("Hisi regulator driver");
+MODULE_DESCRIPTION("Hi6421v600 regulator driver");
 MODULE_LICENSE("GPL v2");
 
diff --git a/include/linux/mfd/hisi_pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h
similarity index 100%
rename from include/linux/mfd/hisi_pmic.h
rename to include/linux/mfd/hi6421-spmi-pmic.h
-- 
2.26.2


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

* [PATCH 18/33] mfd: hi6421-spmi-pmic: get rid of unused OF properties
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (16 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 17/33] mfd: pmic: add drivers for hi6421v600 Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 19/33] spmi: hi6421-spmi-pmic: cleanup " Mauro Carvalho Chehab
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones, linux-kernel

There are several OF properties that aren't used by Hikey 970,
and some are not even used inside the driver.

So, drop them, as as this makes easier to document what's
actually used.

If latter needed, those could be re-added later.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hi6421-spmi-pmic.c       | 145 +--------------------------
 include/linux/mfd/hi6421-spmi-pmic.h |  14 +--
 2 files changed, 7 insertions(+), 152 deletions(-)

diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
index 939f7bd5d8ba..f523b2d844b9 100644
--- a/drivers/mfd/hi6421-spmi-pmic.c
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -49,7 +49,6 @@
 /*#define HISI_NR_IRQ			25*/
 #define HISI_MASK_FIELD		0xFF
 #define HISI_BITS			8
-#define PMIC_FPGA_FLAG          1
 
 /*define the first group interrupt register number*/
 #define HISI_PMIC_FIRST_GROUP_INT_NUM        2
@@ -144,24 +143,6 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 		}
 	}
 
-	/*Handle the second group irq if analysis the second group irq from dtsi*/
-	if (pmic->g_extinterrupt_flag == 1) {
-		for (i = 0; i < pmic->irqarray1; i++) {
-			pending = hisi_pmic_read(pmic, (i + pmic->irq_addr1.start_addr));
-			pending &= HISI_MASK_FIELD;
-			if (pending != 0)
-				pr_debug("pending[%d]=0x%lx\n\r", i, pending);
-
-			hisi_pmic_write(pmic, (i + pmic->irq_addr1.start_addr), pending);
-
-			if (!pending)
-				continue;
-
-			for_each_set_bit(offset, &pending, HISI_BITS)
-				generic_handle_irq(pmic->irqs[offset + (i + HISI_PMIC_FIRST_GROUP_INT_NUM) * HISI_BITS]);
-		}
-	}
-
 	return IRQ_HANDLED;
 }
 
@@ -172,19 +153,8 @@ static void hisi_irq_mask(struct irq_data *d)
 	unsigned long flags;
 
 	offset = (irqd_to_hwirq(d) >> 3);
-	if (pmic->g_extinterrupt_flag == 1) {
-		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM) {
-			offset += pmic->irq_mask_addr.start_addr;
-		} else {
-			/*
-			 * Change addr when irq num larger than 16 because
-			 * interrupt addr is nonsequence
-			 */
-			offset = offset + (pmic->irq_mask_addr1.start_addr) - HISI_PMIC_FIRST_GROUP_INT_NUM;
-		}
-	} else {
-		offset += pmic->irq_mask_addr.start_addr;
-	}
+	offset += pmic->irq_mask_addr.start_addr;
+
 	spin_lock_irqsave(&pmic->lock, flags);
 	data = hisi_pmic_read(pmic, offset);
 	data |= (1 << (irqd_to_hwirq(d) & 0x07));
@@ -199,14 +169,8 @@ static void hisi_irq_unmask(struct irq_data *d)
 	unsigned long flags;
 
 	offset = (irqd_to_hwirq(d) >> 3);
-	if (pmic->g_extinterrupt_flag == 1) {
-		if (offset < HISI_PMIC_FIRST_GROUP_INT_NUM)
-			offset += pmic->irq_mask_addr.start_addr;
-		else
-			offset = offset + (pmic->irq_mask_addr1.start_addr) - HISI_PMIC_FIRST_GROUP_INT_NUM;
-	} else {
-		offset += pmic->irq_mask_addr.start_addr;
-	}
+	offset += pmic->irq_mask_addr.start_addr;
+
 	spin_lock_irqsave(&pmic->lock, flags);
 	data = hisi_pmic_read(pmic, offset);
 	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
@@ -280,69 +244,6 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 		return ret;
 	}
 
-	/*pmic lock*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-lock",
-					 (int *)&pmic->normal_lock, 2);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-lock property set\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
-	/*pmic debug lock*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-debug-lock",
-					 (int *)&pmic->debug_lock, 2);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-debug-lock property set\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
-	return ret;
-}
-
-static int get_pmic_device_tree_data1(struct device_node *np, struct hisi_pmic *pmic)
-{
-	int ret = 0;
-
-	/*get pmic irq num*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num1",
-					 &pmic->irqnum1, 1);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-num1 property set\n");
-		ret = -ENODEV;
-		pmic->irqnum1 = 0;
-		return ret;
-	}
-
-	/*get pmic irq array number*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array1",
-					 &pmic->irqarray1, 1);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-array1 property set\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
-	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr1",
-					 (int *)&pmic->irq_mask_addr1, 2);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-mask-addr1 property set\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
-	/*SOC_PMIC_IRQ0_ADDR*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr1",
-					 (int *)&pmic->irq_addr1, 2);
-	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-addr1 property set\n");
-		ret = -ENODEV;
-		return ret;
-	}
-
-	pmic->g_extinterrupt_flag = 1;
 	return ret;
 }
 
@@ -362,26 +263,6 @@ static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
 	}
 }
 
-static void hisi_pmic_irq1_prc(struct hisi_pmic *pmic)
-{
-	int i;
-	unsigned int pending1;
-
-	if (pmic->g_extinterrupt_flag == 1) {
-		for (i = 0 ; i < pmic->irq_mask_addr1.array; i++)
-			hisi_pmic_write(pmic, pmic->irq_mask_addr1.start_addr + i, HISI_MASK_STATE);
-
-		for (i = 0 ; i < pmic->irq_addr1.array; i++) {
-			pending1 = hisi_pmic_read(pmic, pmic->irq_addr1.start_addr + i);
-
-			pr_debug("PMU IRQ address1 value:irq[0x%x] = 0x%x\n",
-				 pmic->irq_addr1.start_addr + i, pending1);
-
-			hisi_pmic_write(pmic, pmic->irq_addr1.start_addr + i, HISI_MASK_STATE);
-		}
-	}
-}
-
 static int hisi_pmic_probe(struct spmi_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -390,7 +271,6 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	enum of_gpio_flags flags;
 	int ret = 0;
 	int i;
-	unsigned int fpga_flag = 0;
 	unsigned int virq;
 
 	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
@@ -404,22 +284,10 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 		return ret;
 	}
 
-	/*get pmic dts the second group irq*/
-	ret = get_pmic_device_tree_data1(np, pmic);
-	if (ret)
-		dev_err(&pdev->dev, "the platform don't support ext-interrupt.\n");
-
 	/* TODO: get and enable clk request */
 	spin_lock_init(&pmic->lock);
 
 	pmic->dev = dev;
-	ret = of_property_read_u32_array(np, "hisilicon,pmic_fpga_flag",
-					 &fpga_flag, 1);
-	if (ret)
-		pr_err("no hisilicon,pmic_fpga_flag property set\n");
-
-	if (fpga_flag == PMIC_FPGA_FLAG)
-		goto after_irq_register;
 
 	pmic->gpio = of_get_gpio_flags(np, 0, &flags);
 	if (pmic->gpio < 0)
@@ -438,10 +306,6 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 
 	/* mask && clear IRQ status */
 	hisi_pmic_irq_prc(pmic);
-	/*clear && mask the new adding irq*/
-	hisi_pmic_irq1_prc(pmic);
-
-	pmic->irqnum += pmic->irqnum1;
 
 	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
 	if (!pmic->irqs)
@@ -491,7 +355,6 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 		return ret;
 	}
 
-after_irq_register:
 	return 0;
 
 request_theaded_irq:
diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h
index 1f986dd5f31c..41b61de48259 100644
--- a/include/linux/mfd/hi6421-spmi-pmic.h
+++ b/include/linux/mfd/hi6421-spmi-pmic.h
@@ -48,19 +48,11 @@ struct hisi_pmic {
 	struct irq_domain	*domain;
 	int			irq;
 	int			gpio;
-	unsigned int	*irqs;
+	unsigned int		*irqs;
 	int			irqnum;
 	int			irqarray;
-	struct irq_mask_info irq_mask_addr;
-	struct irq_info irq_addr;
-	int			irqnum1;
-	int			irqarray1;
-	struct irq_mask_info irq_mask_addr1;
-	struct irq_info irq_addr1;
-	struct write_lock normal_lock;
-	struct write_lock debug_lock;
-
-	unsigned int g_extinterrupt_flag;
+	struct irq_mask_info 	irq_mask_addr;
+	struct irq_info		irq_addr;
 };
 
 u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
-- 
2.26.2


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

* [PATCH 19/33] spmi: hi6421-spmi-pmic: cleanup OF properties
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (17 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 18/33] mfd: hi6421-spmi-pmic: get rid of unused OF properties Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 20/33] regulator: hi6421v600-regulator: cleanup struct hisi_regulator Mauro Carvalho Chehab
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones, linux-kernel

Simplify the names of the DT properties and do some cleanups,
in order to better document them.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hi6421-spmi-pmic.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
index f523b2d844b9..aed2d3ec2227 100644
--- a/drivers/mfd/hi6421-spmi-pmic.c
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -209,37 +209,37 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 	int ret = 0;
 
 	/*get pmic irq num*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-num",
+	ret = of_property_read_u32_array(np, "irq-num",
 					 &pmic->irqnum, 1);
 	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-num property set\n");
+		pr_err("no irq-num property set\n");
 		ret = -ENODEV;
 		return ret;
 	}
 
 	/*get pmic irq array number*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-array",
+	ret = of_property_read_u32_array(np, "irq-array",
 					 &pmic->irqarray, 1);
 	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-array property set\n");
+		pr_err("no irq-array property set\n");
 		ret = -ENODEV;
 		return ret;
 	}
 
 	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-mask-addr",
+	ret = of_property_read_u32_array(np, "irq-mask-addr",
 					 (int *)&pmic->irq_mask_addr, 2);
 	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-mask-addr property set\n");
+		pr_err("no irq-mask-addr property set\n");
 		ret = -ENODEV;
 		return ret;
 	}
 
 	/*SOC_PMIC_IRQ0_ADDR*/
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-pmic-irq-addr",
+	ret = of_property_read_u32_array(np, "irq-addr",
 					 (int *)&pmic->irq_addr, 2);
 	if (ret) {
-		pr_err("no hisilicon,hisi-pmic-irq-addr property set\n");
+		pr_err("no irq-addr property set\n");
 		ret = -ENODEV;
 		return ret;
 	}
-- 
2.26.2


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

* [PATCH 20/33] regulator: hi6421v600-regulator: cleanup struct hisi_regulator
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (18 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 19/33] spmi: hi6421-spmi-pmic: cleanup " Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 21/33] regulator: hi6421v600-regulator: cleanup debug messages Mauro Carvalho Chehab
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

There are several fields on this struct that can be removed,
as they already exists at struct regulator_desc.

Remove them, cleaning up the code in the process.

While here, rename it to hi6421v600_regulator_info, in order
to better match the driver's name.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 226 +++++++++--------------
 1 file changed, 92 insertions(+), 134 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 9aaafcbb1a36..7d82d11f4b52 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -39,21 +39,11 @@
 #include <linux/uaccess.h>
 #include <linux/spmi.h>
 
-struct hisi_regulator_register_info {
-	u32 ctrl_reg;
-	u32 enable_mask;
-	u32 eco_mode_mask;
-	u32 vset_reg;
-	u32 vset_mask;
-};
-
-struct hisi_regulator {
-	const char *name;
-	struct hisi_regulator_register_info register_info;
-	u32 off_on_delay;
-	u32 eco_uA;
+struct hi6421v600_regulator {
 	struct regulator_desc rdesc;
 	struct hisi_pmic *pmic;
+	u8 eco_mode_mask;
+	u32 eco_uA;
 };
 
 static DEFINE_MUTEX(enable_mutex);
@@ -62,29 +52,29 @@ static DEFINE_MUTEX(enable_mutex);
  * microseconds after 'since'.
  */
 
-static int hisi_regulator_is_enabled(struct regulator_dev *dev)
+static int hisi_regulator_is_enabled(struct regulator_dev *rdev)
 {
 	u32 reg_val;
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 
-	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	pr_debug("<[%s]: ctrl_reg=0x%x,enable_state=%d>\n",
-		 __func__, sreg->register_info.ctrl_reg,
-		(reg_val & sreg->register_info.enable_mask));
+	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
+	pr_debug("<[%s]: enable_reg=0x%x,enable_state=%d>\n",
+		 __func__, rdev->desc->enable_reg,
+		(reg_val & rdev->desc->enable_mask));
 
-	return ((reg_val & sreg->register_info.enable_mask) != 0);
+	return ((reg_val & rdev->desc->enable_mask) != 0);
 }
 
-static int hisi_regulator_enable(struct regulator_dev *dev)
+static int hisi_regulator_enable(struct regulator_dev *rdev)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 
 	/* keep a distance of off_on_delay from last time disabled */
-	usleep_range(sreg->off_on_delay, sreg->off_on_delay + 1000);
+	usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 1000);
 
-	pr_debug("<[%s]: off_on_delay=%dus>\n", __func__, sreg->off_on_delay);
+	pr_debug("<[%s]: off_on_delay=%dus>\n", __func__, rdev->desc->off_on_delay);
 
 	/* cannot enable more than one regulator at one time */
 	mutex_lock(&enable_mutex);
@@ -92,103 +82,103 @@ static int hisi_regulator_enable(struct regulator_dev *dev)
 		     HISI_REGS_ENA_PROTECT_TIME + 1000);
 
 	/* set enable register */
-	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
-		      sreg->register_info.enable_mask,
-				sreg->register_info.enable_mask);
-	pr_debug("<[%s]: ctrl_reg=0x%x,enable_mask=0x%x>\n",
-		 __func__, sreg->register_info.ctrl_reg,
-		 sreg->register_info.enable_mask);
+	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
+		      rdev->desc->enable_mask,
+				rdev->desc->enable_mask);
+	pr_debug("<[%s]: enable_reg=0x%x,enable_mask=0x%x>\n",
+		 __func__, rdev->desc->enable_reg,
+		 rdev->desc->enable_mask);
 
 	mutex_unlock(&enable_mutex);
 
 	return 0;
 }
 
-static int hisi_regulator_disable(struct regulator_dev *dev)
+static int hisi_regulator_disable(struct regulator_dev *rdev)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 
 	/* set enable register to 0 */
-	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
-		      sreg->register_info.enable_mask, 0);
+	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
+		      rdev->desc->enable_mask, 0);
 
 	return 0;
 }
 
-static int hisi_regulator_get_voltage(struct regulator_dev *dev)
+static int hisi_regulator_get_voltage(struct regulator_dev *rdev)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val, selector;
 
 	/* get voltage selector */
-	reg_val = hisi_pmic_read(pmic, sreg->register_info.vset_reg);
-	pr_debug("<[%s]: vset_reg=0x%x>\n",
-		 __func__, sreg->register_info.vset_reg);
+	reg_val = hisi_pmic_read(pmic, rdev->desc->vsel_reg);
+	pr_debug("<[%s]: vsel_reg=0x%x>\n",
+		 __func__, rdev->desc->vsel_reg);
 
-	selector = (reg_val & sreg->register_info.vset_mask) >>
-				(ffs(sreg->register_info.vset_mask) - 1);
+	selector = (reg_val & rdev->desc->vsel_mask) >>
+				(ffs(rdev->desc->vsel_mask) - 1);
 
-	return sreg->rdesc.ops->list_voltage(dev, selector);
+	return rdev->desc->ops->list_voltage(rdev, selector);
 }
 
-static int hisi_regulator_set_voltage(struct regulator_dev *dev,
+static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
 				      int min_uV, int max_uV, unsigned int *selector)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 vsel;
 	int ret = 0;
 
-	for (vsel = 0; vsel < sreg->rdesc.n_voltages; vsel++) {
-		int uV = sreg->rdesc.volt_table[vsel];
+	for (vsel = 0; vsel < rdev->desc->n_voltages; vsel++) {
+		int uV = rdev->desc->volt_table[vsel];
 		/* Break at the first in-range value */
 		if (min_uV <= uV && uV <= max_uV)
 			break;
 	}
 
 	/* unlikely to happen. sanity test done by regulator core */
-	if (unlikely(vsel == sreg->rdesc.n_voltages))
+	if (unlikely(vsel == rdev->desc->n_voltages))
 		return -EINVAL;
 
 	*selector = vsel;
 	/* set voltage selector */
-	hisi_pmic_rmw(pmic, sreg->register_info.vset_reg,
-		      sreg->register_info.vset_mask,
-		vsel << (ffs(sreg->register_info.vset_mask) - 1));
+	hisi_pmic_rmw(pmic, rdev->desc->vsel_reg,
+		      rdev->desc->vsel_mask,
+		vsel << (ffs(rdev->desc->vsel_mask) - 1));
 
-	pr_debug("<[%s]: vset_reg=0x%x, vset_mask=0x%x, value=0x%x>\n",
+	pr_debug("<[%s]: vsel_reg=0x%x, vsel_mask=0x%x, value=0x%x>\n",
 		 __func__,
-		 sreg->register_info.vset_reg,
-		 sreg->register_info.vset_mask,
-		 vsel << (ffs(sreg->register_info.vset_mask) - 1));
+		 rdev->desc->vsel_reg,
+		 rdev->desc->vsel_mask,
+		 vsel << (ffs(rdev->desc->vsel_mask) - 1));
 
 	return ret;
 }
 
-static unsigned int hisi_regulator_get_mode(struct regulator_dev *dev)
+static unsigned int hisi_regulator_get_mode(struct regulator_dev *rdev)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val;
 
-	reg_val = hisi_pmic_read(pmic, sreg->register_info.ctrl_reg);
-	pr_debug("<[%s]: reg_val=%d, ctrl_reg=0x%x, eco_mode_mask=0x%x>\n",
+	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
+	pr_debug("<[%s]: reg_val=%d, enable_reg=0x%x, eco_mode_mask=0x%x>\n",
 		 __func__, reg_val,
-		sreg->register_info.ctrl_reg,
-		sreg->register_info.eco_mode_mask);
+		rdev->desc->enable_reg,
+		sreg->eco_mode_mask);
 
-	if (reg_val & sreg->register_info.eco_mode_mask)
+	if (reg_val & sreg->eco_mode_mask)
 		return REGULATOR_MODE_IDLE;
 	else
 		return REGULATOR_MODE_NORMAL;
 }
 
-static int hisi_regulator_set_mode(struct regulator_dev *dev,
+static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 				   unsigned int mode)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 eco_mode;
 
@@ -204,23 +194,23 @@ static int hisi_regulator_set_mode(struct regulator_dev *dev,
 	}
 
 	/* set mode */
-	hisi_pmic_rmw(pmic, sreg->register_info.ctrl_reg,
-		      sreg->register_info.eco_mode_mask,
-		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
+	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
+		      sreg->eco_mode_mask,
+		eco_mode << (ffs(sreg->eco_mode_mask) - 1));
 
-	pr_debug("<[%s]: ctrl_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n",
+	pr_debug("<[%s]: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n",
 		 __func__,
-		sreg->register_info.ctrl_reg,
-		sreg->register_info.eco_mode_mask,
-		eco_mode << (ffs(sreg->register_info.eco_mode_mask) - 1));
+		rdev->desc->enable_reg,
+		sreg->eco_mode_mask,
+		eco_mode << (ffs(sreg->eco_mode_mask) - 1));
 	return 0;
 }
 
-static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
+static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *rdev,
 						    int input_uV, int output_uV,
 						    int load_uA)
 {
-	struct hisi_regulator *sreg = rdev_get_drvdata(dev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 
 	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA))
 		return REGULATOR_MODE_NORMAL;
@@ -228,42 +218,43 @@ static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *dev,
 		return REGULATOR_MODE_IDLE;
 }
 
-static int hisi_dt_parse_common(struct hisi_regulator *sreg,
-				struct platform_device *pdev)
+static int hisi_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;
-	struct regulator_desc *rdesc = &sreg->rdesc;
 	unsigned int register_info[3] = {0};
-	int ret = 0;
+	unsigned int *v_table;
+	int ret;
 
-	/* parse .register_info.ctrl_reg */
+	/* parse .register_info.enable_reg */
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-ctrl",
 					 register_info, 3);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-ctrl property set\n");
-		goto dt_parse_common_end;
+		return ret;
 	}
-	sreg->register_info.ctrl_reg = register_info[0];
-	sreg->register_info.enable_mask = register_info[1];
-	sreg->register_info.eco_mode_mask = register_info[2];
+	rdesc->enable_reg = register_info[0];
+	rdesc->enable_mask = register_info[1];
+	sreg->eco_mode_mask = register_info[2];
 
-	/* parse .register_info.vset_reg */
+	/* parse .register_info.vsel_reg */
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset",
 					 register_info, 2);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-vset property set\n");
-		goto dt_parse_common_end;
+		return ret;
 	}
-	sreg->register_info.vset_reg = register_info[0];
-	sreg->register_info.vset_mask = register_info[1];
+	rdesc->vsel_reg = register_info[0];
+	rdesc->vsel_mask = register_info[1];
 
 	/* parse .off-on-delay */
 	ret = of_property_read_u32(np, "hisilicon,hisi-off-on-delay-us",
-				   &sreg->off_on_delay);
+				   &rdesc->off_on_delay);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-off-on-delay-us property set\n");
-		goto dt_parse_common_end;
+		return ret;
 	}
 
 	/* parse .enable_time */
@@ -271,7 +262,7 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 				   &rdesc->enable_time);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-enable-time-us property set\n");
-		goto dt_parse_common_end;
+		return ret;
 	}
 
 	/* parse .eco_uA */
@@ -282,56 +273,24 @@ static int hisi_dt_parse_common(struct hisi_regulator *sreg,
 		ret = 0;
 	}
 
-dt_parse_common_end:
-	return ret;
-}
+	/* parse volt_table */
 
-static int hisi_dt_parse_ldo(struct hisi_regulator *sreg,
-			     struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *np = dev->of_node;
-	struct regulator_desc *rdesc = &sreg->rdesc;
-	unsigned int *v_table;
-	int ret = 0;
+	rdesc->n_voltages = of_property_count_u32_elems(np, "hisilicon,hisi-vset-table");
 
-	/* parse .n_voltages, and .volt_table */
-	ret = of_property_read_u32(np, "hisilicon,hisi-n-voltages",
-				   &rdesc->n_voltages);
-	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-n-voltages property set\n");
-		goto dt_parse_ldo_end;
-	}
-
-	/* alloc space for .volt_table */
 	v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages,
 			       GFP_KERNEL);
-	if (unlikely(!v_table)) {
-		ret = -ENOMEM;
-		dev_err(dev, "no memory for .volt_table\n");
-		goto dt_parse_ldo_end;
-	}
+	if (unlikely(!v_table))
+		return  -ENOMEM;
+	rdesc->volt_table = v_table;
 
 	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset-table",
 					 v_table, rdesc->n_voltages);
 	if (ret) {
 		dev_err(dev, "no hisilicon,hisi-vset-table property set\n");
-		goto dt_parse_ldo_end1;
+		return ret;
 	}
-	rdesc->volt_table = v_table;
 
-	/* parse hisi regulator's dt common part */
-	ret = hisi_dt_parse_common(sreg, pdev);
-	if (ret) {
-		dev_err(dev, "failure in hisi_dt_parse_common\n");
-		goto dt_parse_ldo_end1;
-	}
-
-	return ret;
-
-dt_parse_ldo_end1:
-dt_parse_ldo_end:
-	return ret;
+	return 0;
 }
 
 static struct regulator_ops hisi_ldo_rops = {
@@ -364,7 +323,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	struct device *dev = &pdev->dev;
 	struct regulator_desc *rdesc;
 	struct regulator_dev *rdev;
-	struct hisi_regulator *sreg = NULL;
+	struct hi6421v600_regulator *sreg = NULL;
 	struct regulator_init_data *initdata;
 	struct regulator_config config = { };
 	struct regulation_constraints *constraint;
@@ -401,11 +360,10 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	if (!sreg)
 		return -ENOMEM;
 
-	sreg->name = initdata->constraints.name;
 	sreg->pmic = pmic;
 	rdesc = &sreg->rdesc;
 
-	rdesc->name = sreg->name;
+	rdesc->name = initdata->constraints.name;
 	rdesc->ops = &hisi_ldo_rops;
 	rdesc->type = REGULATOR_VOLTAGE;
 	rdesc->min_uV = initdata->constraints.min_uV;
@@ -415,7 +373,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		initdata->supply_regulator = supplyname;
 
 	/* parse device tree data for regulator specific */
-	ret = hisi_dt_parse_ldo(sreg, pdev);
+	ret = hisi_dt_parse(pdev, sreg, rdesc);
 	if (ret) {
 		dev_err(dev, "device tree parameter parse error!\n");
 		goto hisi_probe_end;
@@ -501,13 +459,13 @@ static int hisi_regulator_probe(struct platform_device *pdev)
 static int hisi_regulator_remove(struct platform_device *pdev)
 {
 	struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev);
-	struct hisi_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 
 	regulator_unregister(rdev);
 
 	/* TODO: should i worry about that? devm_kzalloc */
-	if (sreg->rdesc.volt_table)
-		devm_kfree(&pdev->dev, (unsigned int *)sreg->rdesc.volt_table);
+	if (rdev->desc->volt_table)
+		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
 
 	kfree(sreg);
 
-- 
2.26.2


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

* [PATCH 21/33] regulator: hi6421v600-regulator: cleanup debug messages
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (19 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 20/33] regulator: hi6421v600-regulator: cleanup struct hisi_regulator Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 22/33] regulator: hi6421v600-regulator: use shorter names for OF properties Mauro Carvalho Chehab
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

- use dev_foo() instead of pr_foo();
- cleanup the messages, making them more standard and easier
  to understand.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 76 +++++++++++++++---------
 1 file changed, 47 insertions(+), 29 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 7d82d11f4b52..2d1096ecb277 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -59,9 +59,11 @@ static int hisi_regulator_is_enabled(struct regulator_dev *rdev)
 	struct hisi_pmic *pmic = sreg->pmic;
 
 	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
-	pr_debug("<[%s]: enable_reg=0x%x,enable_state=%d>\n",
+
+	dev_dbg(&rdev->dev,
+		"%s: enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
 		 __func__, rdev->desc->enable_reg,
-		(reg_val & rdev->desc->enable_mask));
+		reg_val, (reg_val & rdev->desc->enable_mask));
 
 	return ((reg_val & rdev->desc->enable_mask) != 0);
 }
@@ -74,7 +76,8 @@ static int hisi_regulator_enable(struct regulator_dev *rdev)
 	/* keep a distance of off_on_delay from last time disabled */
 	usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 1000);
 
-	pr_debug("<[%s]: off_on_delay=%dus>\n", __func__, rdev->desc->off_on_delay);
+	dev_dbg(&rdev->dev, "%s: off_on_delay=%d us\n",
+		__func__, rdev->desc->off_on_delay);
 
 	/* cannot enable more than one regulator at one time */
 	mutex_lock(&enable_mutex);
@@ -85,7 +88,7 @@ static int hisi_regulator_enable(struct regulator_dev *rdev)
 	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
 		      rdev->desc->enable_mask,
 				rdev->desc->enable_mask);
-	pr_debug("<[%s]: enable_reg=0x%x,enable_mask=0x%x>\n",
+	dev_dbg(&rdev->dev, "%s: enable_reg=0x%x, enable_mask=0x%x\n",
 		 __func__, rdev->desc->enable_reg,
 		 rdev->desc->enable_mask);
 
@@ -111,16 +114,20 @@ static int hisi_regulator_get_voltage(struct regulator_dev *rdev)
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val, selector;
+	int vol;
 
 	/* get voltage selector */
 	reg_val = hisi_pmic_read(pmic, rdev->desc->vsel_reg);
-	pr_debug("<[%s]: vsel_reg=0x%x>\n",
-		 __func__, rdev->desc->vsel_reg);
-
 	selector = (reg_val & rdev->desc->vsel_mask) >>
 				(ffs(rdev->desc->vsel_mask) - 1);
 
-	return rdev->desc->ops->list_voltage(rdev, selector);
+	vol = rdev->desc->ops->list_voltage(rdev, selector);
+
+	dev_dbg(&rdev->dev,
+		"%s: vsel_reg=0x%x, val=0x%x, entry=0x%x, voltage=%d mV\n",
+		 __func__, rdev->desc->vsel_reg, reg_val, selector, vol/ 1000);
+
+	return vol;
 }
 
 static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
@@ -129,10 +136,14 @@ static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 vsel;
-	int ret = 0;
+	int uV, ret = 0;
 
 	for (vsel = 0; vsel < rdev->desc->n_voltages; vsel++) {
-		int uV = rdev->desc->volt_table[vsel];
+		uV = rdev->desc->volt_table[vsel];
+		dev_dbg(&rdev->dev,
+			"%s: min %d, max %d, value[%u] = %d\n",
+			__func__, min_uV, max_uV, vsel, uV);
+
 		/* Break at the first in-range value */
 		if (min_uV <= uV && uV <= max_uV)
 			break;
@@ -146,13 +157,14 @@ static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
 	/* set voltage selector */
 	hisi_pmic_rmw(pmic, rdev->desc->vsel_reg,
 		      rdev->desc->vsel_mask,
-		vsel << (ffs(rdev->desc->vsel_mask) - 1));
+		      vsel << (ffs(rdev->desc->vsel_mask) - 1));
 
-	pr_debug("<[%s]: vsel_reg=0x%x, vsel_mask=0x%x, value=0x%x>\n",
+	dev_dbg(&rdev->dev,
+		"%s: vsel_reg=0x%x, vsel_mask=0x%x, value=0x%x, voltage=%d mV\n",
 		 __func__,
 		 rdev->desc->vsel_reg,
 		 rdev->desc->vsel_mask,
-		 vsel << (ffs(rdev->desc->vsel_mask) - 1));
+		 vsel << (ffs(rdev->desc->vsel_mask) - 1), uV / 1000);
 
 	return ret;
 }
@@ -162,17 +174,21 @@ static unsigned int hisi_regulator_get_mode(struct regulator_dev *rdev)
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
 	u32 reg_val;
+	unsigned int mode;
 
 	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
-	pr_debug("<[%s]: reg_val=%d, enable_reg=0x%x, eco_mode_mask=0x%x>\n",
-		 __func__, reg_val,
-		rdev->desc->enable_reg,
-		sreg->eco_mode_mask);
 
 	if (reg_val & sreg->eco_mode_mask)
-		return REGULATOR_MODE_IDLE;
+		mode = REGULATOR_MODE_IDLE;
 	else
-		return REGULATOR_MODE_NORMAL;
+		mode = REGULATOR_MODE_NORMAL;
+
+	dev_dbg(&rdev->dev,
+		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n",
+		 __func__, rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val,
+		 mode == REGULATOR_MODE_IDLE ? "idle" : "normal");
+
+	return mode;
 }
 
 static int hisi_regulator_set_mode(struct regulator_dev *rdev,
@@ -198,7 +214,8 @@ static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 		      sreg->eco_mode_mask,
 		eco_mode << (ffs(sreg->eco_mode_mask) - 1));
 
-	pr_debug("<[%s]: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x>\n",
+	dev_dbg(&rdev->dev,
+		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
 		 __func__,
 		rdev->desc->enable_reg,
 		sreg->eco_mode_mask,
@@ -212,10 +229,13 @@ static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *rdev,
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 
-	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA))
+	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA)) {
+		dev_dbg(&rdev->dev, "%s: normal mode", __func__);
 		return REGULATOR_MODE_NORMAL;
-	else
+	} else {
+		dev_dbg(&rdev->dev, "%s: idle mode", __func__);
 		return REGULATOR_MODE_IDLE;
+	}
 }
 
 static int hisi_dt_parse(struct platform_device *pdev,
@@ -333,7 +353,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 
 	initdata = of_get_regulator_init_data(dev, np, NULL);
 	if (!initdata) {
-		pr_err("get regulator init data error !\n");
+		dev_err(dev, "failed to get regulator data\n");
 		return -EINVAL;
 	}
 
@@ -343,14 +363,14 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	ret = of_property_read_u32_array(np, "hisilicon,valid-modes-mask",
 					 &constraint->valid_modes_mask, 1);
 	if (ret) {
-		pr_err("no hisilicon,valid-modes-mask property set\n");
+		dev_err(dev, "no valid modes mask\n");
 		ret = -ENODEV;
 		return ret;
 	}
 	ret = of_property_read_u32_array(np, "hisilicon,valid-idle-mask",
 					 &temp_modes, 1);
 	if (ret) {
-		pr_err("no hisilicon,valid-modes-mask property set\n");
+		dev_err(dev, "no valid idle mask\n");
 		ret = -ENODEV;
 		return ret;
 	}
@@ -374,10 +394,8 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 
 	/* parse device tree data for regulator specific */
 	ret = hisi_dt_parse(pdev, sreg, rdesc);
-	if (ret) {
-		dev_err(dev, "device tree parameter parse error!\n");
+	if (ret)
 		goto hisi_probe_end;
-	}
 
 	config.dev = &pdev->dev;
 	config.init_data = initdata;
@@ -393,7 +411,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		goto hisi_probe_end;
 	}
 
-	pr_debug("[%s]:valid_modes_mask[0x%x], valid_ops_mask[0x%x]\n",
+	dev_dbg(dev, "%s:valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
 		 rdesc->name,
 		 constraint->valid_modes_mask, constraint->valid_ops_mask);
 
-- 
2.26.2


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

* [PATCH 22/33] regulator: hi6421v600-regulator: use shorter names for OF properties
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (20 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 21/33] regulator: hi6421v600-regulator: cleanup debug messages Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 23/33] regulator: hi6421v600-regulator: better handle modes Mauro Carvalho Chehab
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

Simplify the names of the OF properties, in order to make
them similar to other drivers and to make easier to understand
what each property means.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 52 ++++++++++--------------
 1 file changed, 21 insertions(+), 31 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 2d1096ecb277..e4a64893a7ad 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -196,14 +196,14 @@ static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hisi_pmic *pmic = sreg->pmic;
-	u32 eco_mode;
+	u32 val;
 
 	switch (mode) {
 	case REGULATOR_MODE_NORMAL:
-		eco_mode = HISI_ECO_MODE_DISABLE;
+		val = 0;
 		break;
 	case REGULATOR_MODE_IDLE:
-		eco_mode = HISI_ECO_MODE_ENABLE;
+		val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1);
 		break;
 	default:
 		return -EINVAL;
@@ -211,15 +211,12 @@ static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 
 	/* set mode */
 	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
-		      sreg->eco_mode_mask,
-		eco_mode << (ffs(sreg->eco_mode_mask) - 1));
+		      sreg->eco_mode_mask, val);
 
 	dev_dbg(&rdev->dev,
 		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
-		 __func__,
-		rdev->desc->enable_reg,
-		sreg->eco_mode_mask,
-		eco_mode << (ffs(sreg->eco_mode_mask) - 1));
+		 __func__, rdev->desc->enable_reg, sreg->eco_mode_mask, val);
+
 	return 0;
 }
 
@@ -249,10 +246,10 @@ static int hisi_dt_parse(struct platform_device *pdev,
 	int ret;
 
 	/* parse .register_info.enable_reg */
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-ctrl",
+	ret = of_property_read_u32_array(np, "hi6421-ctrl",
 					 register_info, 3);
 	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-ctrl property set\n");
+		dev_err(dev, "no hi6421-ctrl property set\n");
 		return ret;
 	}
 	rdesc->enable_reg = register_info[0];
@@ -260,33 +257,33 @@ static int hisi_dt_parse(struct platform_device *pdev,
 	sreg->eco_mode_mask = register_info[2];
 
 	/* parse .register_info.vsel_reg */
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset",
+	ret = of_property_read_u32_array(np, "hi6421-vsel",
 					 register_info, 2);
 	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-vset property set\n");
+		dev_err(dev, "no hi6421-vsel property set\n");
 		return ret;
 	}
 	rdesc->vsel_reg = register_info[0];
 	rdesc->vsel_mask = register_info[1];
 
 	/* parse .off-on-delay */
-	ret = of_property_read_u32(np, "hisilicon,hisi-off-on-delay-us",
+	ret = of_property_read_u32(np, "off-on-delay-us",
 				   &rdesc->off_on_delay);
 	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-off-on-delay-us property set\n");
+		dev_err(dev, "no off-on-delay-us property set\n");
 		return ret;
 	}
 
 	/* parse .enable_time */
-	ret = of_property_read_u32(np, "hisilicon,hisi-enable-time-us",
+	ret = of_property_read_u32(np, "startup-delay-us",
 				   &rdesc->enable_time);
 	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-enable-time-us property set\n");
+		dev_err(dev, "no startup-delay-us property set\n");
 		return ret;
 	}
 
 	/* parse .eco_uA */
-	ret = of_property_read_u32(np, "hisilicon,hisi-eco-microamp",
+	ret = of_property_read_u32(np, "eco-microamp",
 				   &sreg->eco_uA);
 	if (ret) {
 		sreg->eco_uA = 0;
@@ -295,7 +292,7 @@ static int hisi_dt_parse(struct platform_device *pdev,
 
 	/* parse volt_table */
 
-	rdesc->n_voltages = of_property_count_u32_elems(np, "hisilicon,hisi-vset-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);
@@ -303,10 +300,10 @@ static int hisi_dt_parse(struct platform_device *pdev,
 		return  -ENOMEM;
 	rdesc->volt_table = v_table;
 
-	ret = of_property_read_u32_array(np, "hisilicon,hisi-vset-table",
+	ret = of_property_read_u32_array(np, "voltage-table",
 					 v_table, rdesc->n_voltages);
 	if (ret) {
-		dev_err(dev, "no hisilicon,hisi-vset-table property set\n");
+		dev_err(dev, "no voltage-table property set\n");
 		return ret;
 	}
 
@@ -329,13 +326,6 @@ static struct regulator_ops hisi_ldo_rops = {
  * Used only for parsing the DT properties
  */
 
-static const struct of_device_id of_hisi_pmic_match_tbl[] = {
-	{
-		.compatible = "hisilicon,hi6421-spmi-pmic-ldo",
-	},
-	{ }
-};
-
 static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 				    struct device_node *np,
 				    struct hisi_pmic *pmic)
@@ -360,14 +350,14 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	/* hisi regulator supports two modes */
 	constraint = &initdata->constraints;
 
-	ret = of_property_read_u32_array(np, "hisilicon,valid-modes-mask",
+	ret = of_property_read_u32_array(np, "valid-modes-mask",
 					 &constraint->valid_modes_mask, 1);
 	if (ret) {
 		dev_err(dev, "no valid modes mask\n");
 		ret = -ENODEV;
 		return ret;
 	}
-	ret = of_property_read_u32_array(np, "hisilicon,valid-idle-mask",
+	ret = of_property_read_u32_array(np, "valid-idle-mask",
 					 &temp_modes, 1);
 	if (ret) {
 		dev_err(dev, "no valid idle mask\n");
@@ -388,7 +378,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	rdesc->type = REGULATOR_VOLTAGE;
 	rdesc->min_uV = initdata->constraints.min_uV;
 
-	supplyname = of_get_property(np, "hisilicon,supply_name", NULL);
+	supplyname = of_get_property(np, "supply_name", NULL);
 	if (supplyname)
 		initdata->supply_regulator = supplyname;
 
-- 
2.26.2


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

* [PATCH 23/33] regulator: hi6421v600-regulator: better handle modes
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (21 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 22/33] regulator: hi6421v600-regulator: use shorter names for OF properties Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 24/33] regulator, mfd: change namespace for HiSilicon SPMI PMIC drivers Mauro Carvalho Chehab
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

Instead of implementing a custom set of properties, set
valid_modes_mask based on having or not a mask for enabling
the eco_mode.

This makes the code clearer, and remove some uneeded props
from DT.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 32 ++++++++----------------
 1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index e4a64893a7ad..bde7fa4d7e8f 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -338,7 +338,6 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	struct regulator_config config = { };
 	struct regulation_constraints *constraint;
 	const char *supplyname = NULL;
-	unsigned int temp_modes;
 	int ret = 0;
 
 	initdata = of_get_regulator_init_data(dev, np, NULL);
@@ -347,25 +346,6 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
-	/* hisi regulator supports two modes */
-	constraint = &initdata->constraints;
-
-	ret = of_property_read_u32_array(np, "valid-modes-mask",
-					 &constraint->valid_modes_mask, 1);
-	if (ret) {
-		dev_err(dev, "no valid modes mask\n");
-		ret = -ENODEV;
-		return ret;
-	}
-	ret = of_property_read_u32_array(np, "valid-idle-mask",
-					 &temp_modes, 1);
-	if (ret) {
-		dev_err(dev, "no valid idle mask\n");
-		ret = -ENODEV;
-		return ret;
-	}
-	constraint->valid_ops_mask |= temp_modes;
-
 	sreg = kzalloc(sizeof(*sreg), GFP_KERNEL);
 	if (!sreg)
 		return -ENOMEM;
@@ -387,6 +367,15 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	if (ret)
 		goto hisi_probe_end;
 
+	/* 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;
@@ -401,8 +390,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		goto hisi_probe_end;
 	}
 
-	dev_dbg(dev, "%s:valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
-		 rdesc->name,
+	dev_dbg(dev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
 		 constraint->valid_modes_mask, constraint->valid_ops_mask);
 
 	dev_set_drvdata(dev, rdev);
-- 
2.26.2


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

* [PATCH 24/33] regulator, mfd: change namespace for HiSilicon SPMI PMIC drivers
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (22 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 23/33] regulator: hi6421v600-regulator: better handle modes Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 25/33] regulator: hi6421v600-regulator: convert to use get/set voltage_sel Mauro Carvalho Chehab
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Liam Girdwood, Mark Brown, linux-kernel

Rename the functions used internally inside the driver in
order for them to follow the driver's name.

While here, get rid of some unused definitions at the
header file.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hi6421-spmi-pmic.c           | 97 +++++++++++++-----------
 drivers/regulator/hi6421v600-regulator.c | 94 +++++++++++------------
 include/linux/mfd/hi6421-spmi-pmic.h     | 51 +++++--------
 3 files changed, 117 insertions(+), 125 deletions(-)

diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
index aed2d3ec2227..09cedfa1e4bb 100644
--- a/drivers/mfd/hi6421-spmi-pmic.c
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -62,7 +62,7 @@ static const struct mfd_cell hi6421v600_devs[] = {
  * Hisilicon SoC use hardware to map PMIC register into SoC mapping.
  * At here, we are accessing SoC register with 32-bit.
  */
-u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
+u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)
 {
 	u32 ret;
 	u8 read_value = 0;
@@ -82,9 +82,9 @@ u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg)
 	}
 	return (u32)read_value;
 }
-EXPORT_SYMBOL(hisi_pmic_read);
+EXPORT_SYMBOL(hi6421_spmi_pmic_read);
 
-void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
+void hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val)
 {
 	u32 ret;
 	struct spmi_device *pdev;
@@ -101,34 +101,36 @@ void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val)
 		return;
 	}
 }
-EXPORT_SYMBOL(hisi_pmic_write);
+EXPORT_SYMBOL(hi6421_spmi_pmic_write);
 
-void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits)
+void hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg,
+			  u32 mask, u32 bits)
 {
 	u32 data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&pmic->lock, flags);
-	data = hisi_pmic_read(pmic, reg) & ~mask;
+	data = hi6421_spmi_pmic_read(pmic, reg) & ~mask;
 	data |= mask & bits;
-	hisi_pmic_write(pmic, reg, data);
+	hi6421_spmi_pmic_write(pmic, reg, data);
 	spin_unlock_irqrestore(&pmic->lock, flags);
 }
-EXPORT_SYMBOL(hisi_pmic_rmw);
+EXPORT_SYMBOL(hi6421_spmi_pmic_rmw);
 
-static irqreturn_t hisi_irq_handler(int irq, void *data)
+static irqreturn_t hi6421_spmi_irq_handler(int irq, void *data)
 {
-	struct hisi_pmic *pmic = (struct hisi_pmic *)data;
+	struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)data;
 	unsigned long pending;
 	int i, offset;
 
 	for (i = 0; i < pmic->irqarray; i++) {
-		pending = hisi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
+		pending = hi6421_spmi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
 		pending &= HISI_MASK_FIELD;
 		if (pending != 0)
 			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
 
-		hisi_pmic_write(pmic, (i + pmic->irq_addr.start_addr), pending);
+		hi6421_spmi_pmic_write(pmic, (i + pmic->irq_addr.start_addr),
+				       pending);
 
 		/* solve powerkey order */
 		if ((i == HISI_IRQ_KEY_NUM) && ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
@@ -146,9 +148,9 @@ static irqreturn_t hisi_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static void hisi_irq_mask(struct irq_data *d)
+static void hi6421_spmi_irq_mask(struct irq_data *d)
 {
-	struct hisi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
 	u32 data, offset;
 	unsigned long flags;
 
@@ -156,15 +158,15 @@ static void hisi_irq_mask(struct irq_data *d)
 	offset += pmic->irq_mask_addr.start_addr;
 
 	spin_lock_irqsave(&pmic->lock, flags);
-	data = hisi_pmic_read(pmic, offset);
+	data = hi6421_spmi_pmic_read(pmic, offset);
 	data |= (1 << (irqd_to_hwirq(d) & 0x07));
-	hisi_pmic_write(pmic, offset, data);
+	hi6421_spmi_pmic_write(pmic, offset, data);
 	spin_unlock_irqrestore(&pmic->lock, flags);
 }
 
-static void hisi_irq_unmask(struct irq_data *d)
+static void hi6421_spmi_irq_unmask(struct irq_data *d)
 {
-	struct hisi_pmic *pmic = irq_data_get_irq_chip_data(d);
+	struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
 	u32 data, offset;
 	unsigned long flags;
 
@@ -172,26 +174,26 @@ static void hisi_irq_unmask(struct irq_data *d)
 	offset += pmic->irq_mask_addr.start_addr;
 
 	spin_lock_irqsave(&pmic->lock, flags);
-	data = hisi_pmic_read(pmic, offset);
+	data = hi6421_spmi_pmic_read(pmic, offset);
 	data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
-	hisi_pmic_write(pmic, offset, data);
+	hi6421_spmi_pmic_write(pmic, offset, data);
 	spin_unlock_irqrestore(&pmic->lock, flags);
 }
 
-static struct irq_chip hisi_pmu_irqchip = {
+static struct irq_chip hi6421_spmi_pmu_irqchip = {
 	.name		= "hisi-irq",
-	.irq_mask	= hisi_irq_mask,
-	.irq_unmask	= hisi_irq_unmask,
-	.irq_disable	= hisi_irq_mask,
-	.irq_enable	= hisi_irq_unmask,
+	.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 hisi_irq_map(struct irq_domain *d, unsigned int virq,
+static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
 			irq_hw_number_t hw)
 {
-	struct hisi_pmic *pmic = d->host_data;
+	struct hi6421_spmi_pmic *pmic = d->host_data;
 
-	irq_set_chip_and_handler_name(virq, &hisi_pmu_irqchip,
+	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);
@@ -199,12 +201,13 @@ static int hisi_irq_map(struct irq_domain *d, unsigned int virq,
 	return 0;
 }
 
-static const struct irq_domain_ops hisi_domain_ops = {
-	.map	= hisi_irq_map,
+static const struct irq_domain_ops hi6421_spmi_domain_ops = {
+	.map	= hi6421_spmi_irq_map,
 	.xlate	= irq_domain_xlate_twocell,
 };
 
-static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *pmic)
+static int get_pmic_device_tree_data(struct device_node *np,
+				     struct hi6421_spmi_pmic *pmic)
 {
 	int ret = 0;
 
@@ -247,27 +250,29 @@ static int get_pmic_device_tree_data(struct device_node *np, struct hisi_pmic *p
 	return ret;
 }
 
-static void hisi_pmic_irq_prc(struct hisi_pmic *pmic)
+static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
 {
 	int i;
 
 	for (i = 0 ; i < pmic->irq_mask_addr.array; i++)
-		hisi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i, HISI_MASK_STATE);
+		hi6421_spmi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i,
+				       HISI_MASK_STATE);
 
 	for (i = 0 ; i < pmic->irq_addr.array; i++) {
-		unsigned int pending = hisi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
+		unsigned int pending = hi6421_spmi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
 
 		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
 			 pmic->irq_addr.start_addr + i, pending);
-		hisi_pmic_write(pmic, pmic->irq_addr.start_addr + i, HISI_MASK_STATE);
+		hi6421_spmi_pmic_write(pmic, pmic->irq_addr.start_addr + i,
+				       HISI_MASK_STATE);
 	}
 }
 
-static int hisi_pmic_probe(struct spmi_device *pdev)
+static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
-	struct hisi_pmic *pmic = NULL;
+	struct hi6421_spmi_pmic *pmic = NULL;
 	enum of_gpio_flags flags;
 	int ret = 0;
 	int i;
@@ -305,14 +310,14 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	pmic->irq = gpio_to_irq(pmic->gpio);
 
 	/* mask && clear IRQ status */
-	hisi_pmic_irq_prc(pmic);
+	hi6421_spmi_pmic_irq_prc(pmic);
 
 	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
 	if (!pmic->irqs)
 		goto irq_malloc;
 
 	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
-					     &hisi_domain_ops, pmic);
+					     &hi6421_spmi_domain_ops, pmic);
 	if (!pmic->domain) {
 		dev_err(dev, "failed irq domain add simple!\n");
 		ret = -ENODEV;
@@ -330,7 +335,7 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 		pr_info("[%s]. pmic->irqs[%d] = %d\n", __func__, i, pmic->irqs[i]);
 	}
 
-	ret = request_threaded_irq(pmic->irq, hisi_irq_handler, NULL,
+	ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
 				   IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
 				   "pmic", pmic);
 	if (ret < 0) {
@@ -365,9 +370,9 @@ static int hisi_pmic_probe(struct spmi_device *pdev)
 	return ret;
 }
 
-static void hisi_pmic_remove(struct spmi_device *pdev)
+static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
 {
-	struct hisi_pmic *pmic = dev_get_drvdata(&pdev->dev);
+	struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
 
 	free_irq(pmic->irq, pmic);
 	gpio_free(pmic->gpio);
@@ -380,15 +385,15 @@ static const struct of_device_id pmic_spmi_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
 
-static struct spmi_driver hisi_pmic_driver = {
+static struct spmi_driver hi6421_spmi_pmic_driver = {
 	.driver = {
 		.name	= "hi6421-spmi-pmic",
 		.of_match_table = pmic_spmi_id_table,
 	},
-	.probe	= hisi_pmic_probe,
-	.remove	= hisi_pmic_remove,
+	.probe	= hi6421_spmi_pmic_probe,
+	.remove	= hi6421_spmi_pmic_remove,
 };
-module_spmi_driver(hisi_pmic_driver);
+module_spmi_driver(hi6421_spmi_pmic_driver);
 
 MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index bde7fa4d7e8f..f77ecea78597 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -41,7 +41,7 @@
 
 struct hi6421v600_regulator {
 	struct regulator_desc rdesc;
-	struct hisi_pmic *pmic;
+	struct hi6421_spmi_pmic *pmic;
 	u8 eco_mode_mask;
 	u32 eco_uA;
 };
@@ -52,13 +52,13 @@ static DEFINE_MUTEX(enable_mutex);
  * microseconds after 'since'.
  */
 
-static int hisi_regulator_is_enabled(struct regulator_dev *rdev)
+static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)
 {
 	u32 reg_val;
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 
-	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
 
 	dev_dbg(&rdev->dev,
 		"%s: enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
@@ -68,10 +68,10 @@ static int hisi_regulator_is_enabled(struct regulator_dev *rdev)
 	return ((reg_val & rdev->desc->enable_mask) != 0);
 }
 
-static int hisi_regulator_enable(struct regulator_dev *rdev)
+static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 
 	/* keep a distance of off_on_delay from last time disabled */
 	usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 1000);
@@ -85,7 +85,7 @@ static int hisi_regulator_enable(struct regulator_dev *rdev)
 		     HISI_REGS_ENA_PROTECT_TIME + 1000);
 
 	/* set enable register */
-	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
 		      rdev->desc->enable_mask,
 				rdev->desc->enable_mask);
 	dev_dbg(&rdev->dev, "%s: enable_reg=0x%x, enable_mask=0x%x\n",
@@ -97,27 +97,27 @@ static int hisi_regulator_enable(struct regulator_dev *rdev)
 	return 0;
 }
 
-static int hisi_regulator_disable(struct regulator_dev *rdev)
+static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 
 	/* set enable register to 0 */
-	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
 		      rdev->desc->enable_mask, 0);
 
 	return 0;
 }
 
-static int hisi_regulator_get_voltage(struct regulator_dev *rdev)
+static int hi6421_spmi_regulator_get_voltage(struct regulator_dev *rdev)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 	u32 reg_val, selector;
 	int vol;
 
 	/* get voltage selector */
-	reg_val = hisi_pmic_read(pmic, rdev->desc->vsel_reg);
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->vsel_reg);
 	selector = (reg_val & rdev->desc->vsel_mask) >>
 				(ffs(rdev->desc->vsel_mask) - 1);
 
@@ -130,11 +130,11 @@ static int hisi_regulator_get_voltage(struct regulator_dev *rdev)
 	return vol;
 }
 
-static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
+static int hi6421_spmi_regulator_set_voltage(struct regulator_dev *rdev,
 				      int min_uV, int max_uV, unsigned int *selector)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 	u32 vsel;
 	int uV, ret = 0;
 
@@ -155,7 +155,7 @@ static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
 
 	*selector = vsel;
 	/* set voltage selector */
-	hisi_pmic_rmw(pmic, rdev->desc->vsel_reg,
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg,
 		      rdev->desc->vsel_mask,
 		      vsel << (ffs(rdev->desc->vsel_mask) - 1));
 
@@ -169,14 +169,14 @@ static int hisi_regulator_set_voltage(struct regulator_dev *rdev,
 	return ret;
 }
 
-static unsigned int hisi_regulator_get_mode(struct regulator_dev *rdev)
+static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 	u32 reg_val;
 	unsigned int mode;
 
-	reg_val = hisi_pmic_read(pmic, rdev->desc->enable_reg);
+	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
 
 	if (reg_val & sreg->eco_mode_mask)
 		mode = REGULATOR_MODE_IDLE;
@@ -191,11 +191,11 @@ static unsigned int hisi_regulator_get_mode(struct regulator_dev *rdev)
 	return mode;
 }
 
-static int hisi_regulator_set_mode(struct regulator_dev *rdev,
+static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
 				   unsigned int mode)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
-	struct hisi_pmic *pmic = sreg->pmic;
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
 	u32 val;
 
 	switch (mode) {
@@ -210,8 +210,8 @@ static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 	}
 
 	/* set mode */
-	hisi_pmic_rmw(pmic, rdev->desc->enable_reg,
-		      sreg->eco_mode_mask, val);
+	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
+			     sreg->eco_mode_mask, val);
 
 	dev_dbg(&rdev->dev,
 		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
@@ -220,7 +220,7 @@ static int hisi_regulator_set_mode(struct regulator_dev *rdev,
 	return 0;
 }
 
-static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *rdev,
+static unsigned int hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
 						    int input_uV, int output_uV,
 						    int load_uA)
 {
@@ -235,7 +235,7 @@ static unsigned int hisi_regulator_get_optimum_mode(struct regulator_dev *rdev,
 	}
 }
 
-static int hisi_dt_parse(struct platform_device *pdev,
+static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 			 struct hi6421v600_regulator *sreg,
 			 struct regulator_desc *rdesc)
 {
@@ -310,25 +310,25 @@ static int hisi_dt_parse(struct platform_device *pdev,
 	return 0;
 }
 
-static struct regulator_ops hisi_ldo_rops = {
-	.is_enabled = hisi_regulator_is_enabled,
-	.enable = hisi_regulator_enable,
-	.disable = hisi_regulator_disable,
+static 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,
-	.get_voltage = hisi_regulator_get_voltage,
-	.set_voltage = hisi_regulator_set_voltage,
-	.get_mode = hisi_regulator_get_mode,
-	.set_mode = hisi_regulator_set_mode,
-	.get_optimum_mode = hisi_regulator_get_optimum_mode,
+	.get_voltage = hi6421_spmi_regulator_get_voltage,
+	.set_voltage = hi6421_spmi_regulator_set_voltage,
+	.get_mode = hi6421_spmi_regulator_get_mode,
+	.set_mode = hi6421_spmi_regulator_set_mode,
+	.get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode,
 };
 
 /*
  * Used only for parsing the DT properties
  */
 
-static int hisi_regulator_probe_ldo(struct platform_device *pdev,
+static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
 				    struct device_node *np,
-				    struct hisi_pmic *pmic)
+				    struct hi6421_spmi_pmic *pmic)
 {
 	struct device *dev = &pdev->dev;
 	struct regulator_desc *rdesc;
@@ -354,7 +354,7 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 	rdesc = &sreg->rdesc;
 
 	rdesc->name = initdata->constraints.name;
-	rdesc->ops = &hisi_ldo_rops;
+	rdesc->ops = &hi6421_spmi_ldo_rops;
 	rdesc->type = REGULATOR_VOLTAGE;
 	rdesc->min_uV = initdata->constraints.min_uV;
 
@@ -363,9 +363,9 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		initdata->supply_regulator = supplyname;
 
 	/* parse device tree data for regulator specific */
-	ret = hisi_dt_parse(pdev, sreg, rdesc);
+	ret = hi6421_spmi_dt_parse(pdev, sreg, rdesc);
 	if (ret)
-		goto hisi_probe_end;
+		goto probe_end;
 
 	/* hisi regulator supports two modes */
 	constraint = &initdata->constraints;
@@ -387,27 +387,27 @@ static int hisi_regulator_probe_ldo(struct platform_device *pdev,
 		dev_err(dev, "failed to register %s\n",
 			rdesc->name);
 		ret = PTR_ERR(rdev);
-		goto hisi_probe_end;
+		goto probe_end;
 	}
 
 	dev_dbg(dev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
 		 constraint->valid_modes_mask, constraint->valid_ops_mask);
 
 	dev_set_drvdata(dev, rdev);
-hisi_probe_end:
+probe_end:
 	if (ret)
 		kfree(sreg);
 	return ret;
 }
 
 
-static int hisi_regulator_probe(struct platform_device *pdev)
+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 hisi_pmic *pmic;
+	struct hi6421_spmi_pmic *pmic;
 	int ret;
 
 	dev_dbg(&pdev->dev, "probing hi6421v600 regulator\n");
@@ -442,7 +442,7 @@ static int hisi_regulator_probe(struct platform_device *pdev)
 			continue;
 		}
 
-		ret = hisi_regulator_probe_ldo(new_pdev, child, pmic);
+		ret = hi6421_spmi_regulator_probe_ldo(new_pdev, child, pmic);
 		if (ret < 0)
 			platform_device_put(new_pdev);
 	}
@@ -452,7 +452,7 @@ static int hisi_regulator_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int hisi_regulator_remove(struct platform_device *pdev)
+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);
@@ -479,8 +479,8 @@ static struct platform_driver hi6421v600_regulator_driver = {
 	.driver = {
 		.name	= "hi6421v600-regulator",
 	},
-	.probe	= hisi_regulator_probe,
-	.remove	= hisi_regulator_remove,
+	.probe	= hi6421_spmi_regulator_probe,
+	.remove	= hi6421_spmi_regulator_remove,
 };
 module_platform_driver(hi6421v600_regulator_driver);
 
diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h
index 41b61de48259..d12ad7484018 100644
--- a/include/linux/mfd/hi6421-spmi-pmic.h
+++ b/include/linux/mfd/hi6421-spmi-pmic.h
@@ -17,49 +17,36 @@
 #define HISI_ECO_MODE_ENABLE		(1)
 #define HISI_ECO_MODE_DISABLE		(0)
 
-typedef int (*pmic_ocp_callback)(char *);
-int hisi_pmic_special_ocp_register(char *power_name, pmic_ocp_callback handler);
-
-struct irq_mask_info {
+struct hi6421_spmi_irq_mask_info {
 	int start_addr;
 	int array;
 };
 
-struct irq_info {
+struct hi6421_spmi_irq_info {
 	int start_addr;
 	int array;
 };
 
-struct bit_info {
-	int addr;
-	int bit;
-};
-
-struct write_lock {
-	int addr;
-	int val;
-};
-
-struct hisi_pmic {
-	struct resource		*res;
-	struct device		*dev;
-	void __iomem		*regs;
-	spinlock_t		lock;
-	struct irq_domain	*domain;
-	int			irq;
-	int			gpio;
-	unsigned int		*irqs;
-	int			irqnum;
-	int			irqarray;
-	struct irq_mask_info 	irq_mask_addr;
-	struct irq_info		irq_addr;
+struct hi6421_spmi_pmic {
+	struct resource				*res;
+	struct device				*dev;
+	void __iomem				*regs;
+	spinlock_t				lock;
+	struct irq_domain			*domain;
+	int					irq;
+	int					gpio;
+	unsigned int				*irqs;
+	int					irqnum;
+	int					irqarray;
+	struct hi6421_spmi_irq_mask_info 	irq_mask_addr;
+	struct hi6421_spmi_irq_info		irq_addr;
 };
 
-u32 hisi_pmic_read(struct hisi_pmic *pmic, int reg);
-void hisi_pmic_write(struct hisi_pmic *pmic, int reg, u32 val);
-void hisi_pmic_rmw(struct hisi_pmic *pmic, int reg, u32 mask, u32 bits);
+u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg);
+void hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val);
+void hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg, u32 mask, u32 bits);
 
-enum pmic_irq_list {
+enum hi6421_spmi_pmic_irq_list {
 	OTMP = 0,
 	VBUS_CONNECT,
 	VBUS_DISCONNECT,
-- 
2.26.2


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

* [PATCH 25/33] regulator: hi6421v600-regulator:  convert to use get/set voltage_sel
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (23 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 24/33] regulator, mfd: change namespace for HiSilicon SPMI PMIC drivers Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 26/33] regulator: hi6421v600-regulator: don't use usleep_range for off_on_delay Mauro Carvalho Chehab
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

As the supported LDOs on this driver are all using a selector,
change the implementation to use get_voltage_sel and
set_voltage_sel ops.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 58 +++++++++---------------
 1 file changed, 22 insertions(+), 36 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index f77ecea78597..abd1f43dd5ec 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -86,8 +86,8 @@ static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev)
 
 	/* set enable register */
 	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
-		      rdev->desc->enable_mask,
-				rdev->desc->enable_mask);
+			     rdev->desc->enable_mask,
+			     rdev->desc->enable_mask);
 	dev_dbg(&rdev->dev, "%s: enable_reg=0x%x, enable_mask=0x%x\n",
 		 __func__, rdev->desc->enable_reg,
 		 rdev->desc->enable_mask);
@@ -109,64 +109,49 @@ static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
 	return 0;
 }
 
-static int hi6421_spmi_regulator_get_voltage(struct regulator_dev *rdev)
+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;
-	int vol;
 
 	/* 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);
 
-	vol = rdev->desc->ops->list_voltage(rdev, selector);
+	selector = (reg_val & rdev->desc->vsel_mask) >>	(ffs(rdev->desc->vsel_mask) - 1);
 
 	dev_dbg(&rdev->dev,
-		"%s: vsel_reg=0x%x, val=0x%x, entry=0x%x, voltage=%d mV\n",
-		 __func__, rdev->desc->vsel_reg, reg_val, selector, vol/ 1000);
+		"%s: vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n",
+		 __func__, rdev->desc->vsel_reg, reg_val, selector,
+		rdev->desc->ops->list_voltage(rdev, selector) / 1000);
 
-	return vol;
+	return selector;
 }
 
-static int hi6421_spmi_regulator_set_voltage(struct regulator_dev *rdev,
-				      int min_uV, int max_uV, unsigned int *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 vsel;
-	int uV, ret = 0;
-
-	for (vsel = 0; vsel < rdev->desc->n_voltages; vsel++) {
-		uV = rdev->desc->volt_table[vsel];
-		dev_dbg(&rdev->dev,
-			"%s: min %d, max %d, value[%u] = %d\n",
-			__func__, min_uV, max_uV, vsel, uV);
-
-		/* Break at the first in-range value */
-		if (min_uV <= uV && uV <= max_uV)
-			break;
-	}
+	u32 reg_val;
 
 	/* unlikely to happen. sanity test done by regulator core */
-	if (unlikely(vsel == rdev->desc->n_voltages))
+	if (unlikely(selector >= rdev->desc->n_voltages))
 		return -EINVAL;
 
-	*selector = vsel;
+	reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1);
+
 	/* set voltage selector */
 	hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg,
-		      rdev->desc->vsel_mask,
-		      vsel << (ffs(rdev->desc->vsel_mask) - 1));
+			     rdev->desc->vsel_mask, reg_val);
 
 	dev_dbg(&rdev->dev,
-		"%s: vsel_reg=0x%x, vsel_mask=0x%x, value=0x%x, voltage=%d mV\n",
+		"%s: vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n",
 		 __func__,
-		 rdev->desc->vsel_reg,
-		 rdev->desc->vsel_mask,
-		 vsel << (ffs(rdev->desc->vsel_mask) - 1), uV / 1000);
+		 rdev->desc->vsel_reg, rdev->desc->vsel_mask, reg_val,
+		 rdev->desc->ops->list_voltage(rdev, selector) / 1000);
 
-	return ret;
+	return 0;
 }
 
 static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
@@ -315,8 +300,9 @@ static struct regulator_ops hi6421_spmi_ldo_rops = {
 	.enable = hi6421_spmi_regulator_enable,
 	.disable = hi6421_spmi_regulator_disable,
 	.list_voltage = regulator_list_voltage_table,
-	.get_voltage = hi6421_spmi_regulator_get_voltage,
-	.set_voltage = hi6421_spmi_regulator_set_voltage,
+	.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,
-- 
2.26.2


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

* [PATCH 26/33] regulator: hi6421v600-regulator: don't use usleep_range for off_on_delay
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (24 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 25/33] regulator: hi6421v600-regulator: convert to use get/set voltage_sel Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 27/33] regulator: hi6421v600-regulator: add a driver-specific debug macro Mauro Carvalho Chehab
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

The regulator's core already handles it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index abd1f43dd5ec..31b8ff19fd31 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -73,9 +73,6 @@ 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;
 
-	/* keep a distance of off_on_delay from last time disabled */
-	usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 1000);
-
 	dev_dbg(&rdev->dev, "%s: off_on_delay=%d us\n",
 		__func__, rdev->desc->off_on_delay);
 
-- 
2.26.2


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

* [PATCH 27/33] regulator: hi6421v600-regulator: add a driver-specific debug macro
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (25 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 26/33] regulator: hi6421v600-regulator: don't use usleep_range for off_on_delay Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 28/33] regulator: hi6421v600-regulator: initialize ramp_delay Mauro Carvalho Chehab
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

Using dev_dbg() is not too nice, as, instead of printing the
name of the regulator, it prints "regulator.<number>", making
harder to associate what is happening with each ldo line.

So, add a debug-specific macro, which will print the rdev's
name, just like the regulator core.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 61 +++++++++++++-----------
 1 file changed, 32 insertions(+), 29 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 31b8ff19fd31..5ddaf7f8cacc 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -39,6 +39,9 @@
 #include <linux/uaccess.h>
 #include <linux/spmi.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;
@@ -60,10 +63,10 @@ static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev)
 
 	reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg);
 
-	dev_dbg(&rdev->dev,
-		"%s: enable_reg=0x%x, val= 0x%x, enable_state=%d\n",
-		 __func__, rdev->desc->enable_reg,
-		reg_val, (reg_val & rdev->desc->enable_mask));
+	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);
 }
@@ -73,21 +76,20 @@ 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;
 
-	dev_dbg(&rdev->dev, "%s: off_on_delay=%d us\n",
-		__func__, rdev->desc->off_on_delay);
-
 	/* 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);
-	dev_dbg(&rdev->dev, "%s: enable_reg=0x%x, enable_mask=0x%x\n",
-		 __func__, rdev->desc->enable_reg,
-		 rdev->desc->enable_mask);
 
 	mutex_unlock(&enable_mutex);
 
@@ -100,6 +102,9 @@ static int hi6421_spmi_regulator_disable(struct regulator_dev *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);
 
@@ -117,9 +122,9 @@ static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev)
 
 	selector = (reg_val & rdev->desc->vsel_mask) >>	(ffs(rdev->desc->vsel_mask) - 1);
 
-	dev_dbg(&rdev->dev,
-		"%s: vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n",
-		 __func__, rdev->desc->vsel_reg, reg_val, selector,
+	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;
@@ -139,15 +144,14 @@ static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev,
 	reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1);
 
 	/* set voltage selector */
-	hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg,
-			     rdev->desc->vsel_mask, reg_val);
-
-	dev_dbg(&rdev->dev,
-		"%s: vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n",
-		 __func__,
+	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;
 }
 
@@ -165,9 +169,9 @@ static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
 	else
 		mode = REGULATOR_MODE_NORMAL;
 
-	dev_dbg(&rdev->dev,
-		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n",
-		 __func__, rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val,
+	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;
@@ -192,13 +196,12 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
 	}
 
 	/* 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);
 
-	dev_dbg(&rdev->dev,
-		"%s: enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n",
-		 __func__, rdev->desc->enable_reg, sreg->eco_mode_mask, val);
-
 	return 0;
 }
 
@@ -209,10 +212,10 @@ static unsigned int hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 
 	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA)) {
-		dev_dbg(&rdev->dev, "%s: normal mode", __func__);
+		rdev_dbg(rdev, "normal mode");
 		return REGULATOR_MODE_NORMAL;
 	} else {
-		dev_dbg(&rdev->dev, "%s: idle mode", __func__);
+		rdev_dbg(rdev, "idle mode");
 		return REGULATOR_MODE_IDLE;
 	}
 }
@@ -373,7 +376,7 @@ static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
 		goto probe_end;
 	}
 
-	dev_dbg(dev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n",
+	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);
-- 
2.26.2


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

* [PATCH 28/33] regulator: hi6421v600-regulator: initialize ramp_delay
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (26 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 27/33] regulator: hi6421v600-regulator: add a driver-specific debug macro Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 29/33] regulator: hi6421v600-regulator: cleanup DT settings Mauro Carvalho Chehab
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

Without that, the regulator's core complains with:

       ldo17: ramp_delay not set

For now, use the enable time, as we don't have any datasheets from
this device.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 5ddaf7f8cacc..21467fce9980 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -267,6 +267,9 @@ static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 		return ret;
 	}
 
+	/* FIXME: are there a better value for this? */
+	rdesc->ramp_delay = rdesc->enable_time;
+
 	/* parse .eco_uA */
 	ret = of_property_read_u32(np, "eco-microamp",
 				   &sreg->eco_uA);
-- 
2.26.2


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

* [PATCH 29/33] regulator: hi6421v600-regulator: cleanup DT settings
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (27 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 28/33] regulator: hi6421v600-regulator: initialize ramp_delay Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 30/33] mfd, spmi, regulator: fix some coding style issues at HiSilicon SPMI PMIC Mauro Carvalho Chehab
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Liam Girdwood,
	Mark Brown, linux-kernel

Currently, an array is used to store both vsel and enable
settings, mixing registers, masks and bit settings.

Change it in order to have one separate property for each.

This makes easier to understand the contents of the DT
file, and to describe it at the Documentation/.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/regulator/hi6421v600-regulator.c | 69 ++++++++++++++----------
 1 file changed, 42 insertions(+), 27 deletions(-)

diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 21467fce9980..72f51594b5ff 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -45,8 +45,7 @@
 struct hi6421v600_regulator {
 	struct regulator_desc rdesc;
 	struct hi6421_spmi_pmic *pmic;
-	u8 eco_mode_mask;
-	u32 eco_uA;
+	u32 eco_mode_mask, eco_uA;
 };
 
 static DEFINE_MUTEX(enable_mutex);
@@ -226,36 +225,49 @@ static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
-	unsigned int register_info[3] = {0};
 	unsigned int *v_table;
 	int ret;
 
-	/* parse .register_info.enable_reg */
-	ret = of_property_read_u32_array(np, "hi6421-ctrl",
-					 register_info, 3);
+	ret = of_property_read_u32(np, "reg", &rdesc->enable_reg);
 	if (ret) {
-		dev_err(dev, "no hi6421-ctrl property set\n");
+		dev_err(dev, "missing reg property\nn");
 		return ret;
 	}
-	rdesc->enable_reg = register_info[0];
-	rdesc->enable_mask = register_info[1];
-	sreg->eco_mode_mask = register_info[2];
 
-	/* parse .register_info.vsel_reg */
-	ret = of_property_read_u32_array(np, "hi6421-vsel",
-					 register_info, 2);
+	ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg);
 	if (ret) {
-		dev_err(dev, "no hi6421-vsel property set\n");
+		dev_err(dev, "missing vsel-reg property\n");
 		return ret;
 	}
-	rdesc->vsel_reg = register_info[0];
-	rdesc->vsel_mask = register_info[1];
+
+	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, "no off-on-delay-us property set\n");
+		dev_err(dev, "missing off-on-delay-us property\n");
 		return ret;
 	}
 
@@ -263,21 +275,13 @@ static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 	ret = of_property_read_u32(np, "startup-delay-us",
 				   &rdesc->enable_time);
 	if (ret) {
-		dev_err(dev, "no startup-delay-us property set\n");
+		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 .eco_uA */
-	ret = of_property_read_u32(np, "eco-microamp",
-				   &sreg->eco_uA);
-	if (ret) {
-		sreg->eco_uA = 0;
-		ret = 0;
-	}
-
 	/* parse volt_table */
 
 	rdesc->n_voltages = of_property_count_u32_elems(np, "voltage-table");
@@ -291,10 +295,21 @@ static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 	ret = of_property_read_u32_array(np, "voltage-table",
 					 v_table, rdesc->n_voltages);
 	if (ret) {
-		dev_err(dev, "no voltage-table property set\n");
+		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",
+		rdesc->vsel_reg, rdesc->vsel_mask);
+
 	return 0;
 }
 
-- 
2.26.2


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

* [PATCH 30/33] mfd, spmi, regulator: fix some coding style issues at HiSilicon SPMI PMIC
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (28 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 29/33] regulator: hi6421v600-regulator: cleanup DT settings Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Liam Girdwood, Mark Brown, Stephen Boyd, linux-kernel,
	linux-arm-msm

Checkpatch complains about some minor issues inside the
new mft/regulator/spmi drivers for HiSilicon 6421v600.

Address them.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 drivers/mfd/hi6421-spmi-pmic.c           |  4 ++--
 drivers/regulator/hi6421v600-regulator.c | 28 ++++++++++++------------
 drivers/spmi/spmi.c                      |  5 ++++-
 include/linux/mfd/hi6421-spmi-pmic.h     |  3 ++-
 4 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
index 09cedfa1e4bb..d8b84d64041e 100644
--- a/drivers/mfd/hi6421-spmi-pmic.c
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -189,7 +189,7 @@ static struct irq_chip hi6421_spmi_pmu_irqchip = {
 };
 
 static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
-			irq_hw_number_t hw)
+			       irq_hw_number_t hw)
 {
 	struct hi6421_spmi_pmic *pmic = d->host_data;
 
@@ -350,7 +350,7 @@ static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
 	 * The logic below will rely that the pmic is already stored at
 	 * drvdata.
 	 */
-	dev_dbg(&pdev->dev, "SPMI-PMIC: adding childs for %pOF\n",
+	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),
diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c
index 72f51594b5ff..c80dfac1e4c3 100644
--- a/drivers/regulator/hi6421v600-regulator.c
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -40,7 +40,7 @@
 #include <linux/spmi.h>
 
 #define rdev_dbg(rdev, fmt, arg...)	\
-		 pr_debug("%s: %s: " fmt, rdev->desc->name, __func__, ##arg)
+		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)
 
 struct hi6421v600_regulator {
 	struct regulator_desc rdesc;
@@ -105,7 +105,7 @@ static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev)
 		 rdev->desc->enable_reg, rdev->desc->enable_mask);
 
 	hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg,
-		      rdev->desc->enable_mask, 0);
+			     rdev->desc->enable_mask, 0);
 
 	return 0;
 }
@@ -122,7 +122,7 @@ static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev)
 	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",
+		 "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);
 
@@ -144,7 +144,7 @@ static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev,
 
 	/* set voltage selector */
 	rdev_dbg(rdev,
-		"vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n",
+		 "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);
 
@@ -169,7 +169,7 @@ static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
 		mode = REGULATOR_MODE_NORMAL;
 
 	rdev_dbg(rdev,
-		"enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n",
+		 "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");
 
@@ -177,7 +177,7 @@ static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev)
 }
 
 static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
-				   unsigned int mode)
+					  unsigned int mode)
 {
 	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
 	struct hi6421_spmi_pmic *pmic = sreg->pmic;
@@ -204,9 +204,10 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev,
 	return 0;
 }
 
-static unsigned int hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev,
-						    int input_uV, int output_uV,
-						    int load_uA)
+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);
 
@@ -220,7 +221,7 @@ static unsigned int hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev
 }
 
 static int hi6421_spmi_dt_parse(struct platform_device *pdev,
-			 struct hi6421v600_regulator *sreg,
+				struct hi6421v600_regulator *sreg,
 			 struct regulator_desc *rdesc)
 {
 	struct device *dev = &pdev->dev;
@@ -256,7 +257,7 @@ static int hi6421_spmi_dt_parse(struct platform_device *pdev,
 		sreg->eco_uA = 0;
 	} else {
 		ret = of_property_read_u32(np, "eco-microamp",
-					&sreg->eco_uA);
+					   &sreg->eco_uA);
 		if (ret) {
 			dev_err(dev, "missing eco-microamp property\n");
 			return ret;
@@ -331,8 +332,8 @@ static struct regulator_ops hi6421_spmi_ldo_rops = {
  */
 
 static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
-				    struct device_node *np,
-				    struct hi6421_spmi_pmic *pmic)
+					   struct device_node *np,
+					   struct hi6421_spmi_pmic *pmic)
 {
 	struct device *dev = &pdev->dev;
 	struct regulator_desc *rdesc;
@@ -404,7 +405,6 @@ static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
 	return ret;
 }
 
-
 static int hi6421_spmi_regulator_probe(struct platform_device *pdev)
 {
 	struct device *pmic_dev = pdev->dev.parent;
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index fd3ff6079b15..253340e10dab 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -23,6 +23,7 @@ static DEFINE_IDA(ctrl_ida);
 static void spmi_dev_release(struct device *dev)
 {
 	struct spmi_device *sdev = to_spmi_device(dev);
+
 	kfree(sdev);
 }
 
@@ -33,6 +34,7 @@ static const struct device_type spmi_dev_type = {
 static void spmi_ctrl_release(struct device *dev)
 {
 	struct spmi_controller *ctrl = to_spmi_controller(dev);
+
 	ida_simple_remove(&ctrl_ida, ctrl->nr);
 	kfree(ctrl);
 }
@@ -487,7 +489,7 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
 			continue;
 
 		sdev->dev.of_node = node;
-		sdev->usid = (u8) reg[0];
+		sdev->usid = (u8)reg[0];
 
 		err = spmi_device_add(sdev);
 		if (err) {
@@ -531,6 +533,7 @@ EXPORT_SYMBOL_GPL(spmi_controller_add);
 static int spmi_ctrl_remove_device(struct device *dev, void *data)
 {
 	struct spmi_device *spmidev = to_spmi_device(dev);
+
 	if (dev->type == &spmi_dev_type)
 		spmi_device_remove(spmidev);
 	return 0;
diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h
index d12ad7484018..aeff96c4a37e 100644
--- a/include/linux/mfd/hi6421-spmi-pmic.h
+++ b/include/linux/mfd/hi6421-spmi-pmic.h
@@ -38,7 +38,8 @@ struct hi6421_spmi_pmic {
 	unsigned int				*irqs;
 	int					irqnum;
 	int					irqarray;
-	struct hi6421_spmi_irq_mask_info 	irq_mask_addr;
+
+	struct hi6421_spmi_irq_mask_info	irq_mask_addr;
 	struct hi6421_spmi_irq_info		irq_addr;
 };
 
-- 
2.26.2


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

* [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (29 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 30/33] mfd, spmi, regulator: fix some coding style issues at HiSilicon SPMI PMIC Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-12 16:30   ` Rob Herring
  2020-08-11 15:41 ` [PATCH 32/33] dt: hisilicon: add support for the PMIC found on Hikey 970 Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  34 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Lee Jones,
	Rob Herring, Stephen Boyd, devicetree, linux-kernel,
	linux-arm-msm

Add documentation for the properties needed by the HiSilicon
6421v600 driver, and by the SPMI controller used to access
the chipset.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 175 ++++++++++++++++++
 .../spmi/hisilicon,hisi-spmi-controller.yaml  |  54 ++++++
 2 files changed, 229 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.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..33dcbaeb474e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/hisilicon,hi6421v600-regulator.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 uses a MIPI System Power Management (SPMI) bus in order
+  to provide 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
+  Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml.
+
+properties:
+  $nodename:
+    pattern: "pmic@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,hi6421-spmi-pmic
+
+  reg:
+    maxItems: 1
+
+  spmi-channel:
+    description: number of the SPMI channel where the PMIC is connected
+
+  '#interrupt-cells':
+    const: 2
+
+  interrupt-controller:
+    description:
+      Identify that the PMIC is capable of behaving as an interrupt controller.
+
+  gpios:
+    maxItems: 1
+
+  irq-num:
+    description: Interrupt request number
+
+  'irq-array':
+    description: Interrupt request array
+
+  'irq-mask-addr':
+    description: Address for the interrupt request mask
+
+  'irq-addr':
+    description: Address for the interrupt request
+
+  regulators:
+    type: object
+
+    properties:
+      '#address-cells':
+        const: 1
+
+      '#size-cells':
+        const: 0
+
+    patternProperties:
+      '^ldo@[0-9]+$':
+        type: object
+
+        $ref: "/schemas/regulator/regulator.yaml#"
+
+        properties:
+          reg:
+            description: Enable register.
+
+          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
+  - spmi-channel
+  - regulators
+
+examples:
+  - |
+    pmic: pmic@0 {
+      compatible = "hisilicon,hi6421-spmi-pmic";
+      slave_id = <0>;
+      reg = <0 0>;
+
+      #interrupt-cells = <2>;
+      interrupt-controller;
+      gpios = <&gpio28 0 0>;
+      irq-num = <16>;
+      irq-array = <2>;
+      irq-mask-addr = <0x202 2>;
+      irq-addr = <0x212 2>;
+
+      regulators {
+        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/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..d087f9067e4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
@@ -0,0 +1,54 @@
+# 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 controller is found on some Kirin-based designs.
+  It is a MIPI System Power Management (SPMI) controller.
+
+  The PMIC part is provided by
+  Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
+
+properties:
+  $nodename:
+    pattern: "spmi@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,spmi-controller
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 0
+
+  spmi-channel:
+    const: number of the SPMI channel where the PMIC is connected
+
+patternProperties:
+  "^pmic@[0-9a-f]$":
+    $ref: "/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#"
+
+examples:
+  - |
+    spmi: spmi@fff24000 {
+      compatible = "hisilicon,spmi-controller";
+      #address-cells = <2>;
+      #size-cells = <0>;
+      status = "ok";
+      reg = <0x0 0xfff24000 0x0 0x1000>;
+      spmi-channel = <2>;
+
+      /* pmic properties */
+
+    };
-- 
2.26.2


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

* [PATCH 32/33] dt: hisilicon: add support for the PMIC found on Hikey 970
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (30 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:41 ` [PATCH 33/33] MAINTAINERS: add an entry for HiSilicon 6421v600 drivers Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, Wei Xu,
	Rob Herring, linux-arm-kernel, devicetree, 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.

We'll keep the 3v3 fixed regulator, as this will be used
by the DRM/KMS driver. So, let's just rename it.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../boot/dts/hisilicon/hi3670-hikey970.dts    |  16 +-
 .../boot/dts/hisilicon/hikey970-pmic.dtsi     | 200 ++++++++++++++++++
 2 files changed, 204 insertions(+), 12 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 01234a175dcd..c8a72c0873bf 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,7 +40,7 @@ memory@0 {
 		reg = <0x0 0x0 0x0 0x0>;
 	};
 
-	sd_1v8: regulator-1v8 {
+	fixed_1v8: regulator-1v8 {
 		compatible = "regulator-fixed";
 		regulator-name = "fixed-1.8V";
 		regulator-min-microvolt = <1800000>;
@@ -47,15 +48,6 @@ sd_1v8: regulator-1v8 {
 		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";
@@ -402,8 +394,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..2a6c366d9be6
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
@@ -0,0 +1,200 @@
+// 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.
+ */
+
+/ {
+	spmi: spmi@fff24000 {
+		compatible = "hisilicon,spmi-controller";
+		#address-cells = <2>;
+		#size-cells = <0>;
+		status = "ok";
+		reg = <0x0 0xfff24000 0x0 0x1000>;
+		spmi-channel = <2>;
+
+		pmic: pmic@0 {
+			compatible = "hisilicon,hi6421-spmi-pmic";
+			slave_id = <0>;
+			reg = <0 0>;
+
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			gpios = <&gpio28 0 0>;
+			irq-num = <16>;
+			irq-array = <2>;
+			irq-mask-addr = <0x202 2>;
+			irq-addr = <0x212 2>;
+
+			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.26.2


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

* [PATCH 33/33] MAINTAINERS: add an entry for HiSilicon 6421v600 drivers
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (31 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 32/33] dt: hisilicon: add support for the PMIC found on Hikey 970 Mauro Carvalho Chehab
@ 2020-08-11 15:41 ` Mauro Carvalho Chehab
  2020-08-11 15:54 ` [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
  2020-08-11 16:09 ` Mark Brown
  34 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:41 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, Mauro Carvalho Chehab, David S. Miller,
	Rob Herring, linux-kernel

Add an entry for the SPMI, MFD and PMIC parts of the
HiSilicon 6421v600 support.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 956ecd5ba426..6410df78e301 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7736,6 +7736,14 @@ F:	include/linux/hippidevice.h
 F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 
+HISILICON 6421v600 SPMI PMIC DRIVER
+M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/mfd/hi6421-spmi-pmic.c
+F:	drivers/regulator/hi6421v600-regulator.c
+F:	drivers/spmi/spmi.c
+
 HISILICON DMA DRIVER
 M:	Zhou Wang <wangzhou1@hisilicon.com>
 L:	dmaengine@vger.kernel.org
-- 
2.26.2


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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (32 preceding siblings ...)
  2020-08-11 15:41 ` [PATCH 33/33] MAINTAINERS: add an entry for HiSilicon 6421v600 drivers Mauro Carvalho Chehab
@ 2020-08-11 15:54 ` Mauro Carvalho Chehab
  2020-08-11 17:51   ` Jonathan Cameron
  2020-08-11 16:09 ` Mark Brown
  34 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 15:54 UTC (permalink / raw)
  Cc: linuxarm, mauro.chehab, linux-arm-msm, Liam Girdwood,
	linux-arm-kernel, Rob Herring, David S. Miller, Mark Brown,
	Rob Herring, Wei Xu, Stephen Boyd, Lee Jones, devicetree,
	Mayulong, linux-kernel

Em Tue, 11 Aug 2020 17:41:26 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> escreveu:

> The Hikey 970 board uses a different PMIC than the one found on Hikey 960.
> 
> This PMIC uses a SPMI board.
> 
> This patch series backport the OOT drivers from the Linaro's official
> tree for this board:
> 
> 	https://github.com/96boards-hikey/linux/tree/hikey970-v4.9
> 	
> Porting them to upstream, cleaning up coding style issues, solving
> driver probing order and adding DT documentation.
> 
> I opted to not fold all patches into a single one, in order to:
> 
> - Preserve the authorship of the original authors;
> - Keep a history of changes.
> 
> As this could be harder for people to review, I'll be replying to patch 00/32
> with all patches folded. This should help reviewers to see the current
> code after the entire series is applied.

As promised, it follows the diff from this entire patch series.

Feel free to review either on the top of this e-mail or on the
individual patches.

Thanks!
Mauro

 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml      | 175 ++++++++++++++++++++++++++++++++++++++
 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml |  54 ++++++++++++
 MAINTAINERS                                                                |   8 ++
 arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts                          |  16 +---
 arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi                           | 200 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/Kconfig                                                        |  17 +++-
 drivers/mfd/Makefile                                                       |   1 +
 drivers/mfd/hi6421-spmi-pmic.c                                             | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/regulator/Kconfig                                                  |   8 ++
 drivers/regulator/Makefile                                                 |   1 +
 drivers/regulator/hi6421v600-regulator.c                                   | 493 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/spmi/Kconfig                                                       |   9 ++
 drivers/spmi/Makefile                                                      |   2 +
 drivers/spmi/hisi-spmi-controller.c                                        | 384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/spmi/spmi.c                                                        |  10 +--
 include/linux/mfd/hi6421-spmi-pmic.h                                       |  67 +++++++++++++++
 16 files changed, 1826 insertions(+), 18 deletions(-)


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..33dcbaeb474e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/hisilicon,hi6421v600-regulator.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 uses a MIPI System Power Management (SPMI) bus in order
+  to provide 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
+  Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml.
+
+properties:
+  $nodename:
+    pattern: "pmic@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,hi6421-spmi-pmic
+
+  reg:
+    maxItems: 1
+
+  spmi-channel:
+    description: number of the SPMI channel where the PMIC is connected
+
+  '#interrupt-cells':
+    const: 2
+
+  interrupt-controller:
+    description:
+      Identify that the PMIC is capable of behaving as an interrupt controller.
+
+  gpios:
+    maxItems: 1
+
+  irq-num:
+    description: Interrupt request number
+
+  'irq-array':
+    description: Interrupt request array
+
+  'irq-mask-addr':
+    description: Address for the interrupt request mask
+
+  'irq-addr':
+    description: Address for the interrupt request
+
+  regulators:
+    type: object
+
+    properties:
+      '#address-cells':
+        const: 1
+
+      '#size-cells':
+        const: 0
+
+    patternProperties:
+      '^ldo@[0-9]+$':
+        type: object
+
+        $ref: "/schemas/regulator/regulator.yaml#"
+
+        properties:
+          reg:
+            description: Enable register.
+
+          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
+  - spmi-channel
+  - regulators
+
+examples:
+  - |
+    pmic: pmic@0 {
+      compatible = "hisilicon,hi6421-spmi-pmic";
+      slave_id = <0>;
+      reg = <0 0>;
+
+      #interrupt-cells = <2>;
+      interrupt-controller;
+      gpios = <&gpio28 0 0>;
+      irq-num = <16>;
+      irq-array = <2>;
+      irq-mask-addr = <0x202 2>;
+      irq-addr = <0x212 2>;
+
+      regulators {
+        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/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..d087f9067e4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
@@ -0,0 +1,54 @@
+# 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 controller is found on some Kirin-based designs.
+  It is a MIPI System Power Management (SPMI) controller.
+
+  The PMIC part is provided by
+  Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
+
+properties:
+  $nodename:
+    pattern: "spmi@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,spmi-controller
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 0
+
+  spmi-channel:
+    const: number of the SPMI channel where the PMIC is connected
+
+patternProperties:
+  "^pmic@[0-9a-f]$":
+    $ref: "/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#"
+
+examples:
+  - |
+    spmi: spmi@fff24000 {
+      compatible = "hisilicon,spmi-controller";
+      #address-cells = <2>;
+      #size-cells = <0>;
+      status = "ok";
+      reg = <0x0 0xfff24000 0x0 0x1000>;
+      spmi-channel = <2>;
+
+      /* pmic properties */
+
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 956ecd5ba426..6410df78e301 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7736,6 +7736,14 @@ F:	include/linux/hippidevice.h
 F:	include/uapi/linux/if_hippi.h
 F:	net/802/hippi.c
 
+HISILICON 6421v600 SPMI PMIC DRIVER
+M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/mfd/hi6421-spmi-pmic.c
+F:	drivers/regulator/hi6421v600-regulator.c
+F:	drivers/spmi/spmi.c
+
 HISILICON DMA DRIVER
 M:	Zhou Wang <wangzhou1@hisilicon.com>
 L:	dmaengine@vger.kernel.org
diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
index 01234a175dcd..c8a72c0873bf 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,7 +40,7 @@ memory@0 {
 		reg = <0x0 0x0 0x0 0x0>;
 	};
 
-	sd_1v8: regulator-1v8 {
+	fixed_1v8: regulator-1v8 {
 		compatible = "regulator-fixed";
 		regulator-name = "fixed-1.8V";
 		regulator-min-microvolt = <1800000>;
@@ -47,15 +48,6 @@ sd_1v8: regulator-1v8 {
 		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";
@@ -402,8 +394,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..2a6c366d9be6
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
@@ -0,0 +1,200 @@
+// 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.
+ */
+
+/ {
+	spmi: spmi@fff24000 {
+		compatible = "hisilicon,spmi-controller";
+		#address-cells = <2>;
+		#size-cells = <0>;
+		status = "ok";
+		reg = <0x0 0xfff24000 0x0 0x1000>;
+		spmi-channel = <2>;
+
+		pmic: pmic@0 {
+			compatible = "hisilicon,hi6421-spmi-pmic";
+			slave_id = <0>;
+			reg = <0 0>;
+
+			#interrupt-cells = <2>;
+			interrupt-controller;
+			gpios = <&gpio28 0 0>;
+			irq-num = <16>;
+			irq-array = <2>;
+			irq-mask-addr = <0x202 2>;
+			irq-addr = <0x212 2>;
+
+			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>;
+				};
+			};
+		};
+	};
+};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a37d7d171382..04c249649532 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -493,10 +493,25 @@ config MFD_HI6421_PMIC
 	  Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi-
 	  functions, such as regulators, RTC, codec, Coulomb counter, etc.
 	  This driver includes core APIs _only_. You have to select
-	  individul components like voltage regulators under corresponding
+	  individual components like voltage regulators under corresponding
 	  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
+	select MFD_CORE
+	select REGMAP_MMIO
+	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 9367a92f795a..2ac0727dafc9 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..d8b84d64041e
--- /dev/null
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -0,0 +1,399 @@
+// 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/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/irq.h>
+#include <linux/spmi.h>
+#ifndef NO_IRQ
+#define NO_IRQ       0
+#endif
+
+/* 8-bit register offset in PMIC */
+#define HISI_MASK_STATE			0xff
+
+#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_NR_IRQ			25*/
+#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.
+ */
+u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)
+{
+	u32 ret;
+	u8 read_value = 0;
+	struct spmi_device *pdev;
+
+	pdev = to_spmi_device(pmic->dev);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
+		return 0;
+	}
+
+	ret = spmi_ext_register_readl(pdev, reg,
+				      (unsigned char *)&read_value, 1);
+	if (ret) {
+		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
+		return 0;
+	}
+	return (u32)read_value;
+}
+EXPORT_SYMBOL(hi6421_spmi_pmic_read);
+
+void hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val)
+{
+	u32 ret;
+	struct spmi_device *pdev;
+
+	pdev = to_spmi_device(pmic->dev);
+	if (!pdev) {
+		pr_err("%s: pdev get failed!\n", __func__);
+		return;
+	}
+
+	ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1);
+	if (ret) {
+		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
+		return;
+	}
+}
+EXPORT_SYMBOL(hi6421_spmi_pmic_write);
+
+void hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg,
+			  u32 mask, u32 bits)
+{
+	u32 data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pmic->lock, flags);
+	data = hi6421_spmi_pmic_read(pmic, reg) & ~mask;
+	data |= mask & bits;
+	hi6421_spmi_pmic_write(pmic, reg, data);
+	spin_unlock_irqrestore(&pmic->lock, flags);
+}
+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 < pmic->irqarray; i++) {
+		pending = hi6421_spmi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
+		pending &= HISI_MASK_FIELD;
+		if (pending != 0)
+			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
+
+		hi6421_spmi_pmic_write(pmic, (i + pmic->irq_addr.start_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 += pmic->irq_mask_addr.start_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 += pmic->irq_mask_addr.start_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 int get_pmic_device_tree_data(struct device_node *np,
+				     struct hi6421_spmi_pmic *pmic)
+{
+	int ret = 0;
+
+	/*get pmic irq num*/
+	ret = of_property_read_u32_array(np, "irq-num",
+					 &pmic->irqnum, 1);
+	if (ret) {
+		pr_err("no irq-num property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*get pmic irq array number*/
+	ret = of_property_read_u32_array(np, "irq-array",
+					 &pmic->irqarray, 1);
+	if (ret) {
+		pr_err("no irq-array property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
+	ret = of_property_read_u32_array(np, "irq-mask-addr",
+					 (int *)&pmic->irq_mask_addr, 2);
+	if (ret) {
+		pr_err("no irq-mask-addr property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/*SOC_PMIC_IRQ0_ADDR*/
+	ret = of_property_read_u32_array(np, "irq-addr",
+					 (int *)&pmic->irq_addr, 2);
+	if (ret) {
+		pr_err("no irq-addr property set\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	return ret;
+}
+
+static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
+{
+	int i;
+
+	for (i = 0 ; i < pmic->irq_mask_addr.array; i++)
+		hi6421_spmi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i,
+				       HISI_MASK_STATE);
+
+	for (i = 0 ; i < pmic->irq_addr.array; i++) {
+		unsigned int pending = hi6421_spmi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
+
+		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
+			 pmic->irq_addr.start_addr + i, pending);
+		hi6421_spmi_pmic_write(pmic, pmic->irq_addr.start_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 = NULL;
+	enum of_gpio_flags flags;
+	int ret = 0;
+	int i;
+	unsigned int virq;
+
+	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	/*TODO: get pmic dts info*/
+	ret = get_pmic_device_tree_data(np, pmic);
+	if (ret) {
+		dev_err(&pdev->dev, "Error reading hisi pmic dts\n");
+		return ret;
+	}
+
+	/* TODO: get and enable clk request */
+	spin_lock_init(&pmic->lock);
+
+	pmic->dev = dev;
+
+	pmic->gpio = of_get_gpio_flags(np, 0, &flags);
+	if (pmic->gpio < 0)
+		return pmic->gpio;
+
+	if (!gpio_is_valid(pmic->gpio))
+		return -EINVAL;
+
+	ret = gpio_request_one(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);
+
+	/* mask && clear IRQ status */
+	hi6421_spmi_pmic_irq_prc(pmic);
+
+	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
+	if (!pmic->irqs)
+		goto irq_malloc;
+
+	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
+					     &hi6421_spmi_domain_ops, pmic);
+	if (!pmic->domain) {
+		dev_err(dev, "failed irq domain add simple!\n");
+		ret = -ENODEV;
+		goto irq_domain;
+	}
+
+	for (i = 0; i < pmic->irqnum; i++) {
+		virq = irq_create_mapping(pmic->domain, i);
+		if (virq == NO_IRQ) {
+			pr_debug("Failed mapping hwirq\n");
+			ret = -ENOSPC;
+			goto irq_create_mapping;
+		}
+		pmic->irqs[i] = virq;
+		pr_info("[%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 %d\n", ret);
+		ret = -ENODEV;
+		goto request_theaded_irq;
+	}
+
+	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) {
+		dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+
+request_theaded_irq:
+irq_create_mapping:
+irq_domain:
+irq_malloc:
+	gpio_free(pmic->gpio);
+	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);
+	gpio_free(pmic->gpio);
+	devm_kfree(&pdev->dev, pmic);
+}
+
+static const struct of_device_id pmic_spmi_id_table[] = {
+	{ .compatible = "hisilicon,hi6421-spmi-pmic" },
+	{ }
+};
+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/regulator/Kconfig b/drivers/regulator/Kconfig
index edb1c4f8b496..de8a78487bb9 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -356,6 +356,14 @@ config REGULATOR_HI6421V530
 	  provides 5 general purpose LDOs, and all of them come with support
 	  to either ECO (idle) or sleep mode.
 
+config REGULATOR_HI6421V600
+	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
+	depends on MFD_HI6421_PMIC && OF
+	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_HI655X
 	tristate "Hisilicon HI655X PMIC regulators support"
 	depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0796e4a47afa..f59d5e3b5fd4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.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..c80dfac1e4c3
--- /dev/null
+++ b/drivers/regulator/hi6421v600-regulator.c
@@ -0,0 +1,493 @@
+// 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/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/spmi.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)
+{
+	u32 reg_val;
+	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
+	struct hi6421_spmi_pmic *pmic = sreg->pmic;
+
+	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;
+
+	/* unlikely to happen. sanity test done by regulator core */
+	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;
+	u32 reg_val;
+	unsigned int mode;
+
+	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)) {
+		rdev_dbg(rdev, "normal mode");
+		return REGULATOR_MODE_NORMAL;
+	} else {
+		rdev_dbg(rdev, "idle mode");
+		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\nn");
+		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",
+		rdesc->vsel_reg, rdesc->vsel_mask);
+
+	return 0;
+}
+
+static 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,
+};
+
+/*
+ * Used only for parsing the DT properties
+ */
+
+static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
+					   struct device_node *np,
+					   struct hi6421_spmi_pmic *pmic)
+{
+	struct device *dev = &pdev->dev;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct hi6421v600_regulator *sreg = NULL;
+	struct regulator_init_data *initdata;
+	struct regulator_config config = { };
+	struct regulation_constraints *constraint;
+	const char *supplyname = NULL;
+	int ret = 0;
+
+	initdata = of_get_regulator_init_data(dev, np, NULL);
+	if (!initdata) {
+		dev_err(dev, "failed to get regulator data\n");
+		return -EINVAL;
+	}
+
+	sreg = kzalloc(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)
+		goto probe_end;
+
+	/* 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);
+		ret = PTR_ERR(rdev);
+		goto probe_end;
+	}
+
+	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);
+probe_end:
+	if (ret)
+		kfree(sreg);
+	return ret;
+}
+
+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;
+
+	dev_dbg(&pdev->dev, "probing hi6421v600 regulator\n");
+	/*
+	 * 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);
+
+	/* TODO: should i worry about that? devm_kzalloc */
+	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/spmi/Kconfig b/drivers/spmi/Kconfig
index a53bad541f1a..b44e2ab6bf81 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -25,4 +25,13 @@ config SPMI_MSM_PMIC_ARB
 	  This is required for communicating with Qualcomm PMICs and
 	  other devices that have the SPMI interface.
 
+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.
+
 endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 55a94cadeffe..694853e391cb 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -5,3 +5,5 @@
 obj-$(CONFIG_SPMI)	+= spmi.o
 
 obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
+
+obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
new file mode 100644
index 000000000000..153bcdb0cde4
--- /dev/null
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/spmi.h>
+
+#define SPMI_CONTROLLER_NAME		"spmi_controller"
+
+/*
+ * 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
+
+/*
+ * @base base address of the PMIC Arbiter core registers.
+ * @rdbase, @wrbase base address of the PMIC Arbiter read core registers.
+ *     For HW-v1 these are equal to base.
+ *     For HW-v2, the value is the same in eeraly probing, in order to read
+ *     PMIC_ARB_CORE registers, then chnls, and obsrvr are set to
+ *     PMIC_ARB_CORE_REGISTERS and PMIC_ARB_CORE_REGISTERS_OBS respectivly.
+ * @intr base address of the SPMI interrupt control registers
+ * @ppid_2_chnl_tbl lookup table f(SID, Periph-ID) -> channel num
+ *      entry is only valid if corresponding bit is set in valid_ppid_bitmap.
+ * @valid_ppid_bitmap bit is set only for valid ppids.
+ * @fmt_cmd formats a command to be set into PMIC_ARBq_CHNLn_CMD
+ * @chnl_ofst calculates offset of the base of a channel reg space
+ * @ee execution environment id
+ * @irq_acc0_init_val initial value of the interrupt accumulator at probe time.
+ *      Use for an HW workaround. On handling interrupts, the first accumulator
+ *      register will be compared against this value, and bits which are set at
+ *      boot will be ignored.
+ * @reserved_chnl entry of ppid_2_chnl_tbl that this driver should never touch.
+ *      value is positive channel number or negative to mark it unused.
+ */
+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 status = 0;
+	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
+	u32 offset;
+
+	offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
+	offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
+
+	while (timeout--) {
+		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);
+	}
+
+	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 sid, u16 addr, u8 *__buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	unsigned long flags;
+	u8 *buf = __buf;
+	u32 cmd, data;
+	int rc;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+	u8 op_code, i;
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	/* Check the opcode */
+	if (opc == SPMI_CMD_READ) {
+		op_code = SPMI_CMD_REG_READ;
+	} else if (opc == SPMI_CMD_EXT_READ) {
+		op_code = SPMI_CMD_EXT_REG_READ;
+	} else if (opc == SPMI_CMD_EXT_READL) {
+		op_code = SPMI_CMD_EXT_REG_READ_L;
+	} else {
+		dev_err(&ctrl->dev, "invalid read cmd 0x%x", 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) |
+	     ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+	     ((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, sid, addr);
+	if (rc)
+		goto done;
+
+	i = 0;
+	do {
+		data = readl(spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET * sid + 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);
+		}
+		i++;
+	} while (bc > i * 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 sid:%d addr:0x%x bc:%ld\n",
+			opc, sid, addr, bc + 1);
+	else
+		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
+			__func__, sid, addr, (int)bc, __buf);
+
+	return rc;
+}
+
+static int spmi_write_cmd(struct spmi_controller *ctrl,
+			  u8 opc, u8 sid, u16 addr, const u8 *__buf, size_t bc)
+{
+	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+	const u8 *buf = __buf;
+	unsigned long flags;
+	u32 cmd, data;
+	int rc;
+	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+	u8 op_code, i;
+
+	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
+			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+		return  -EINVAL;
+	}
+
+	/* Check the opcode */
+	if (opc == SPMI_CMD_WRITE) {
+		op_code = SPMI_CMD_REG_WRITE;
+	} else if (opc == SPMI_CMD_EXT_WRITE) {
+		op_code = SPMI_CMD_EXT_REG_WRITE;
+	} else if (opc == SPMI_CMD_EXT_WRITEL) {
+		op_code = SPMI_CMD_EXT_REG_WRITE_L;
+	} else {
+		dev_err(&ctrl->dev, "invalid write cmd 0x%x", 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) |
+	      ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+	      ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
+
+	/* Write data to FIFOs */
+	spin_lock_irqsave(&spmi_controller->lock, flags);
+
+	i = 0;
+	do {
+		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);
+		i++;
+	} while (bc > i * SPMI_PER_DATAREG_BYTE);
+
+	/* 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, sid, addr);
+	spin_unlock_irqrestore(&spmi_controller->lock, flags);
+
+	if (rc)
+		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
+			opc, sid, addr, bc);
+	else
+		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
+			__func__, sid, 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 = 0;
+
+	dev_info(&pdev->dev, "HISI SPMI probe\n");
+
+	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;
+
+	/* NOTE: driver uses the static register mapping */
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores) {
+		dev_err(&pdev->dev, "can not get resource!\n");
+		return -EINVAL;
+	}
+
+	spmi_controller->base = ioremap(iores->start, resource_size(iores));
+	if (!spmi_controller->base) {
+		dev_err(&pdev->dev, "can not remap base addr!\n");
+		return -EADDRNOTAVAIL;
+	}
+	dev_dbg(&pdev->dev, "spmi_add_controller base addr=0x%lx!\n",
+		(unsigned long)spmi_controller->base);
+
+	/* Get properties from the device tree */
+	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)
+		goto err_add_controller;
+
+	dev_info(&pdev->dev, "spmi_add_controller initialized\n");
+	return 0;
+
+err_add_controller:
+	dev_err(&pdev->dev, "spmi_add_controller failed!\n");
+	platform_set_drvdata(pdev, NULL);
+	return ret;
+}
+
+static int spmi_del_controller(struct platform_device *pdev)
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	spmi_controller_remove(ctrl);
+	return 0;
+}
+
+static const struct of_device_id spmi_controller_match_table[] = {
+	{	.compatible = "hisilicon,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	= SPMI_CONTROLLER_NAME,
+		.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_controlller");
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index c16b60f645a4..253340e10dab 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -23,6 +23,7 @@ static DEFINE_IDA(ctrl_ida);
 static void spmi_dev_release(struct device *dev)
 {
 	struct spmi_device *sdev = to_spmi_device(dev);
+
 	kfree(sdev);
 }
 
@@ -33,6 +34,7 @@ static const struct device_type spmi_dev_type = {
 static void spmi_ctrl_release(struct device *dev)
 {
 	struct spmi_controller *ctrl = to_spmi_controller(dev);
+
 	ida_simple_remove(&ctrl_ida, ctrl->nr);
 	kfree(ctrl);
 }
@@ -487,7 +489,7 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
 			continue;
 
 		sdev->dev.of_node = node;
-		sdev->usid = (u8) reg[0];
+		sdev->usid = (u8)reg[0];
 
 		err = spmi_device_add(sdev);
 		if (err) {
@@ -531,6 +533,7 @@ EXPORT_SYMBOL_GPL(spmi_controller_add);
 static int spmi_ctrl_remove_device(struct device *dev, void *data)
 {
 	struct spmi_device *spmidev = to_spmi_device(dev);
+
 	if (dev->type == &spmi_dev_type)
 		spmi_device_remove(spmidev);
 	return 0;
@@ -545,13 +548,10 @@ static int spmi_ctrl_remove_device(struct device *dev, void *data)
  */
 void spmi_controller_remove(struct spmi_controller *ctrl)
 {
-	int dummy;
-
 	if (!ctrl)
 		return;
 
-	dummy = device_for_each_child(&ctrl->dev, NULL,
-				      spmi_ctrl_remove_device);
+	device_for_each_child(&ctrl->dev, NULL, spmi_ctrl_remove_device);
 	device_del(&ctrl->dev);
 }
 EXPORT_SYMBOL_GPL(spmi_controller_remove);
diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h
new file mode 100644
index 000000000000..aeff96c4a37e
--- /dev/null
+++ b/include/linux/mfd/hi6421-spmi-pmic.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header file for device driver Hi6421 PMIC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (C) 2011 Hisilicon.
+ *
+ * Guodong Xu <guodong.xu@linaro.org>
+ */
+
+#ifndef	__HISI_PMIC_H
+#define	__HISI_PMIC_H
+
+#include <linux/irqdomain.h>
+
+#define HISI_REGS_ENA_PROTECT_TIME	(0)	/* in microseconds */
+#define HISI_ECO_MODE_ENABLE		(1)
+#define HISI_ECO_MODE_DISABLE		(0)
+
+struct hi6421_spmi_irq_mask_info {
+	int start_addr;
+	int array;
+};
+
+struct hi6421_spmi_irq_info {
+	int start_addr;
+	int array;
+};
+
+struct hi6421_spmi_pmic {
+	struct resource				*res;
+	struct device				*dev;
+	void __iomem				*regs;
+	spinlock_t				lock;
+	struct irq_domain			*domain;
+	int					irq;
+	int					gpio;
+	unsigned int				*irqs;
+	int					irqnum;
+	int					irqarray;
+
+	struct hi6421_spmi_irq_mask_info	irq_mask_addr;
+	struct hi6421_spmi_irq_info		irq_addr;
+};
+
+u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg);
+void hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val);
+void hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg, u32 mask, u32 bits);
+
+enum hi6421_spmi_pmic_irq_list {
+	OTMP = 0,
+	VBUS_CONNECT,
+	VBUS_DISCONNECT,
+	ALARMON_R,
+	HOLD_6S,
+	HOLD_1S,
+	POWERKEY_UP,
+	POWERKEY_DOWN,
+	OCP_SCP_R,
+	COUL_R,
+	SIM0_HPD_R,
+	SIM0_HPD_F,
+	SIM1_HPD_R,
+	SIM1_HPD_F,
+	PMIC_IRQ_LIST_MAX,
+};
+#endif		/* __HISI_PMIC_H */


Thanks,
Mauro

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

* Re: [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC
  2020-08-11 15:41 ` [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC Mauro Carvalho Chehab
@ 2020-08-11 15:58   ` Mark Brown
  2020-08-11 16:08     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 48+ messages in thread
From: Mark Brown @ 2020-08-11 15:58 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, Mayulong, Lee Jones, Liam Girdwood,
	Stephen Boyd, linux-kernel, linux-arm-msm

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

On Tue, Aug 11, 2020 at 05:41:28PM +0200, Mauro Carvalho Chehab wrote:

>  drivers/mfd/hisi_pmic_spmi.c            | 759 ++++++++++++++++++++++++
>  drivers/regulator/hisi_regulator_spmi.c | 741 +++++++++++++++++++++++
>  drivers/spmi/hisi-spmi-controller.c     | 390 ++++++++++++
>  include/linux/mfd/hisi_pmic.h           | 165 ++++++

This is a single patch for three subsystems, please split it into per
subsystem patches.

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

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

* Re: [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC
  2020-08-11 15:41 ` [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC Mauro Carvalho Chehab
@ 2020-08-11 16:00   ` Mark Brown
  0 siblings, 0 replies; 48+ messages in thread
From: Mark Brown @ 2020-08-11 16:00 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, Lee Jones, Liam Girdwood, linux-kernel

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

On Tue, Aug 11, 2020 at 05:41:30PM +0200, Mauro Carvalho Chehab wrote:
> There are some checks there which could make sense for
> downstream builds, but doesn't make much sense for
> upstream ones. They came from the official Hikey970 tree
> from Linaro, but even there, the commented-out code is not
> set via other Kconfig vars.

> So, let's just get rid of that. If needed later, this
> patch can be (partially?) reversed.

> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  drivers/mfd/hisi_pmic_spmi.c            |  63 --------
>  drivers/regulator/hisi_regulator_spmi.c | 196 +-----------------------
>  include/linux/mfd/hisi_pmic.h           |  42 -----
>  3 files changed, 8 insertions(+), 293 deletions(-)

This is fixing stuff added in the previous patch, please just fold these
fixes into the first patch.

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

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

* Re: [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC
  2020-08-11 15:58   ` Mark Brown
@ 2020-08-11 16:08     ` Mauro Carvalho Chehab
  2020-08-11 16:15       ` Mark Brown
  0 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 16:08 UTC (permalink / raw)
  To: Mark Brown
  Cc: linuxarm, mauro.chehab, Mayulong, Lee Jones, Liam Girdwood,
	Stephen Boyd, linux-kernel, linux-arm-msm

Em Tue, 11 Aug 2020 16:58:10 +0100
Mark Brown <broonie@kernel.org> escreveu:

> On Tue, Aug 11, 2020 at 05:41:28PM +0200, Mauro Carvalho Chehab wrote:
> 
> >  drivers/mfd/hisi_pmic_spmi.c            | 759 ++++++++++++++++++++++++
> >  drivers/regulator/hisi_regulator_spmi.c | 741 +++++++++++++++++++++++
> >  drivers/spmi/hisi-spmi-controller.c     | 390 ++++++++++++
> >  include/linux/mfd/hisi_pmic.h           | 165 ++++++  
> 
> This is a single patch for three subsystems, please split it into per
> subsystem patches.

Ok, I'll split on a next version. 


Yet, it would be good to have all tree drivers applied via the same tree,
as those drivers are needed altogether in order for this PMIC to work:

- The SPMI controller driver talks with the hardware and provides
  support via the SPMI bus calls;
- The MFD PMIC driver binds into the SPMI bus and provide support
  for interrupts. It also has support for binding the regulator
  driver;
- The regulator driver needs the PMIC driver (which in turn needs
  the SPMI bus) in order to be able to talk with the hardware and
  set the power supplied.

That's basically why I opted to send the entire series altogether.

Thanks,
Mauro

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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
                   ` (33 preceding siblings ...)
  2020-08-11 15:54 ` [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
@ 2020-08-11 16:09 ` Mark Brown
  34 siblings, 0 replies; 48+ messages in thread
From: Mark Brown @ 2020-08-11 16:09 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, linux-arm-msm, Liam Girdwood,
	linux-arm-kernel, Rob Herring, David S. Miller, Rob Herring,
	Wei Xu, Stephen Boyd, Lee Jones, devicetree, Mayulong,
	linux-kernel

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

On Tue, Aug 11, 2020 at 05:41:26PM +0200, Mauro Carvalho Chehab wrote:

> This patch series backport the OOT drivers from the Linaro's official
> tree for this board:

> 	https://github.com/96boards-hikey/linux/tree/hikey970-v4.9

> Porting them to upstream, cleaning up coding style issues, solving
> driver probing order and adding DT documentation.

> I opted to not fold all patches into a single one, in order to:
> 
> - Preserve the authorship of the original authors;
> - Keep a history of changes.

Please don't do this, please send this as a normal upstream submission
like other MFD drivers - split things up per subsystem and fold any
fixes into the initial submission of the driver.

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

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

* Re: [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC
  2020-08-11 16:08     ` Mauro Carvalho Chehab
@ 2020-08-11 16:15       ` Mark Brown
  2020-08-11 16:35         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 48+ messages in thread
From: Mark Brown @ 2020-08-11 16:15 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linuxarm, mauro.chehab, Mayulong, Lee Jones, Liam Girdwood,
	Stephen Boyd, linux-kernel, linux-arm-msm

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

On Tue, Aug 11, 2020 at 06:08:37PM +0200, Mauro Carvalho Chehab wrote:
> Mark Brown <broonie@kernel.org> escreveu:

> > This is a single patch for three subsystems, please split it into per
> > subsystem patches.

> Ok, I'll split on a next version. 

> Yet, it would be good to have all tree drivers applied via the same tree,
> as those drivers are needed altogether in order for this PMIC to work:

This is completely normal for MFD drivers, it's still much easier to
review things if individual subsystem maintainers can easily get to the
code for their subsystem, any Reviewed-bys or whatever can be sensibly
applies to relevant code and ideally people can apply patches as they're
ready if there's no build time dependencies or Kconfig symbols which
prevent build without the dependencies being merged.

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

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

* Re: [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC
  2020-08-11 16:15       ` Mark Brown
@ 2020-08-11 16:35         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-11 16:35 UTC (permalink / raw)
  To: Mark Brown
  Cc: linuxarm, mauro.chehab, Mayulong, Lee Jones, Liam Girdwood,
	Stephen Boyd, linux-kernel, linux-arm-msm

Em Tue, 11 Aug 2020 17:15:39 +0100
Mark Brown <broonie@kernel.org> escreveu:

> On Tue, Aug 11, 2020 at 06:08:37PM +0200, Mauro Carvalho Chehab wrote:
> > Mark Brown <broonie@kernel.org> escreveu:  
> 
> > > This is a single patch for three subsystems, please split it into per
> > > subsystem patches.  
> 
> > Ok, I'll split on a next version.   
> 
> > Yet, it would be good to have all tree drivers applied via the same tree,
> > as those drivers are needed altogether in order for this PMIC to work:  
> 
> This is completely normal for MFD drivers, it's still much easier to
> review things if individual subsystem maintainers can easily get to the
> code for their subsystem, any Reviewed-bys or whatever can be sensibly
> applies to relevant code and ideally people can apply patches as they're
> ready if there's no build time dependencies or Kconfig symbols which
> prevent build without the dependencies being merged.

Ok. I'll split it into three series. 

Before posting the next version, it would be nice to have some feedback
specially at the DT documentation patch:

	https://lore.kernel.org/lkml/176043f329dfa9889f014feec04e7e1553077873.1597160086.git.mchehab+huawei@kernel.org/T/#u

as any changes there will need to be reflected on the other patches
from this series.

Btw, despite being 3 drivers, I added only two DT docs, as the
regulator description is done together with the PMIC one.

Thanks,
Mauro

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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-11 15:54 ` [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
@ 2020-08-11 17:51   ` Jonathan Cameron
  2020-08-12  7:45     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 48+ messages in thread
From: Jonathan Cameron @ 2020-08-11 17:51 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, linux-kernel, devicetree, Stephen Boyd,
	linux-arm-msm, Mark Brown, Mayulong, linuxarm, Liam Girdwood,
	Rob Herring, Lee Jones, David S. Miller, linux-arm-kernel

On Tue, 11 Aug 2020 17:54:29 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

> Em Tue, 11 Aug 2020 17:41:26 +0200
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> escreveu:
> 
> > The Hikey 970 board uses a different PMIC than the one found on Hikey 960.
> > 
> > This PMIC uses a SPMI board.
> > 
> > This patch series backport the OOT drivers from the Linaro's official
> > tree for this board:
> > 
> > 	https://github.com/96boards-hikey/linux/tree/hikey970-v4.9
> > 	
> > Porting them to upstream, cleaning up coding style issues, solving
> > driver probing order and adding DT documentation.
> > 
> > I opted to not fold all patches into a single one, in order to:
> > 
> > - Preserve the authorship of the original authors;
> > - Keep a history of changes.
> > 
> > As this could be harder for people to review, I'll be replying to patch 00/32
> > with all patches folded. This should help reviewers to see the current
> > code after the entire series is applied.  
> 
> As promised, it follows the diff from this entire patch series.
> 
> Feel free to review either on the top of this e-mail or on the
> individual patches.
> 

Whilst I agree entirely with Mark about the need to turn this into a clean series,
I was bored at the end of the day so here is a drive by review..

I've not looked at anything that really needed any thought as it is too hot for
thinking.

Jonathan

> Thanks!
> Mauro
> 
>  Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml      | 175 ++++++++++++++++++++++++++++++++++++++
>  Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml |  54 ++++++++++++
>  MAINTAINERS                                                                |   8 ++
>  arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts                          |  16 +---
>  arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi                           | 200 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mfd/Kconfig                                                        |  17 +++-
>  drivers/mfd/Makefile                                                       |   1 +
>  drivers/mfd/hi6421-spmi-pmic.c                                             | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/regulator/Kconfig                                                  |   8 ++
>  drivers/regulator/Makefile                                                 |   1 +
>  drivers/regulator/hi6421v600-regulator.c                                   | 493 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spmi/Kconfig                                                       |   9 ++
>  drivers/spmi/Makefile                                                      |   2 +
>  drivers/spmi/hisi-spmi-controller.c                                        | 384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spmi/spmi.c                                                        |  10 +--
>  include/linux/mfd/hi6421-spmi-pmic.h                                       |  67 +++++++++++++++
>  16 files changed, 1826 insertions(+), 18 deletions(-)
> 
> 
> 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..33dcbaeb474e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> @@ -0,0 +1,175 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/hisilicon,hi6421v600-regulator.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 uses a MIPI System Power Management (SPMI) bus in order
> +  to provide 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
> +  Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml.
> +
> +properties:
> +  $nodename:
> +    pattern: "pmic@[0-9a-f]"
> +
> +  compatible:
> +    const: hisilicon,hi6421-spmi-pmic
> +
> +  reg:
> +    maxItems: 1
> +
> +  spmi-channel:
> +    description: number of the SPMI channel where the PMIC is connected
> +
> +  '#interrupt-cells':
> +    const: 2
> +
> +  interrupt-controller:
> +    description:
> +      Identify that the PMIC is capable of behaving as an interrupt controller.
> +
> +  gpios:
> +    maxItems: 1
> +
> +  irq-num:
> +    description: Interrupt request number
> +
> +  'irq-array':
> +    description: Interrupt request array
> +
> +  'irq-mask-addr':
> +    description: Address for the interrupt request mask
> +
> +  'irq-addr':
> +    description: Address for the interrupt request
> +
> +  regulators:
> +    type: object
> +
> +    properties:
> +      '#address-cells':
> +        const: 1
> +
> +      '#size-cells':
> +        const: 0
> +
> +    patternProperties:
> +      '^ldo@[0-9]+$':
> +        type: object
> +
> +        $ref: "/schemas/regulator/regulator.yaml#"
> +
> +        properties:
> +          reg:
> +            description: Enable register.
> +
> +          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

Guess this needs fixing up.

> +
> +          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
> +  - spmi-channel
> +  - regulators
> +
> +examples:
> +  - |
> +    pmic: pmic@0 {
> +      compatible = "hisilicon,hi6421-spmi-pmic";
> +      slave_id = <0>;
> +      reg = <0 0>;
> +
> +      #interrupt-cells = <2>;
> +      interrupt-controller;
> +      gpios = <&gpio28 0 0>;
> +      irq-num = <16>;
> +      irq-array = <2>;
> +      irq-mask-addr = <0x202 2>;
> +      irq-addr = <0x212 2>;
> +
> +      regulators {
> +        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/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..d087f9067e4c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> @@ -0,0 +1,54 @@
> +# 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 controller is found on some Kirin-based designs.
> +  It is a MIPI System Power Management (SPMI) controller.
> +
> +  The PMIC part is provided by
> +  Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
> +
> +properties:
> +  $nodename:
> +    pattern: "spmi@[0-9a-f]"
> +
> +  compatible:
> +    const: hisilicon,spmi-controller
> +
> +  reg:
> +    maxItems: 1
> +
> +  "#address-cells":
> +    const: 2
> +
> +  "#size-cells":
> +    const: 0
> +
> +  spmi-channel:
> +    const: number of the SPMI channel where the PMIC is connected
> +
> +patternProperties:
> +  "^pmic@[0-9a-f]$":
> +    $ref: "/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#"
> +
> +examples:
> +  - |
> +    spmi: spmi@fff24000 {
> +      compatible = "hisilicon,spmi-controller";
> +      #address-cells = <2>;
> +      #size-cells = <0>;
> +      status = "ok";
> +      reg = <0x0 0xfff24000 0x0 0x1000>;
> +      spmi-channel = <2>;
> +
> +      /* pmic properties */
> +
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 956ecd5ba426..6410df78e301 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7736,6 +7736,14 @@ F:	include/linux/hippidevice.h
>  F:	include/uapi/linux/if_hippi.h
>  F:	net/802/hippi.c
>  
> +HISILICON 6421v600 SPMI PMIC DRIVER
> +M:	Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +L:	linux-kernel@vger.kernel.org
> +S:	Maintained
> +F:	drivers/mfd/hi6421-spmi-pmic.c
> +F:	drivers/regulator/hi6421v600-regulator.c
> +F:	drivers/spmi/spmi.c
> +
>  HISILICON DMA DRIVER
>  M:	Zhou Wang <wangzhou1@hisilicon.com>
>  L:	dmaengine@vger.kernel.org
> diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
> index 01234a175dcd..c8a72c0873bf 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,7 +40,7 @@ memory@0 {
>  		reg = <0x0 0x0 0x0 0x0>;
>  	};
>  
> -	sd_1v8: regulator-1v8 {
> +	fixed_1v8: regulator-1v8 {

Rename relevant?

>  		compatible = "regulator-fixed";
>  		regulator-name = "fixed-1.8V";
>  		regulator-min-microvolt = <1800000>;
> @@ -47,15 +48,6 @@ sd_1v8: regulator-1v8 {
>  		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";
> @@ -402,8 +394,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..2a6c366d9be6
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
> @@ -0,0 +1,200 @@
> +// 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.
> + */
> +
> +/ {
> +	spmi: spmi@fff24000 {
> +		compatible = "hisilicon,spmi-controller";
> +		#address-cells = <2>;
> +		#size-cells = <0>;
> +		status = "ok";
> +		reg = <0x0 0xfff24000 0x0 0x1000>;
> +		spmi-channel = <2>;
> +
> +		pmic: pmic@0 {
> +			compatible = "hisilicon,hi6421-spmi-pmic";
> +			slave_id = <0>;
> +			reg = <0 0>;
> +
> +			#interrupt-cells = <2>;
> +			interrupt-controller;
> +			gpios = <&gpio28 0 0>;
> +			irq-num = <16>;
> +			irq-array = <2>;
> +			irq-mask-addr = <0x202 2>;
> +			irq-addr = <0x212 2>;
> +
> +			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>;
> +				};
> +			};
> +		};
> +	};
> +};
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index a37d7d171382..04c249649532 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -493,10 +493,25 @@ config MFD_HI6421_PMIC
>  	  Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi-
>  	  functions, such as regulators, RTC, codec, Coulomb counter, etc.
>  	  This driver includes core APIs _only_. You have to select
> -	  individul components like voltage regulators under corresponding
> +	  individual components like voltage regulators under corresponding

Don't fix other drivers.

>  	  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
> +	select MFD_CORE
> +	select REGMAP_MMIO

Nice thought, but it doesn't use it yet!

> +	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 9367a92f795a..2ac0727dafc9 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..d8b84d64041e
> --- /dev/null
> +++ b/drivers/mfd/hi6421-spmi-pmic.c
> @@ -0,0 +1,399 @@
> +// 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.

Drop license text.

> + *
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_irq.h>
> +#include <linux/mfd/hi6421-spmi-pmic.h>
> +#include <linux/irq.h>
> +#include <linux/spmi.h>
> +#ifndef NO_IRQ
> +#define NO_IRQ       0

Drop

> +#endif
> +
> +/* 8-bit register offset in PMIC */
> +#define HISI_MASK_STATE			0xff
> +
> +#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_NR_IRQ			25*/

Drop

> +#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.
Can we return the 8 bits in an int and hence also return error codes?
> + */
> +u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)
> +{
> +	u32 ret;
> +	u8 read_value = 0;
> +	struct spmi_device *pdev;
> +
> +	pdev = to_spmi_device(pmic->dev);
> +	if (!pdev) {
> +		pr_err("%s: pdev get failed!\n", __func__);
> +		return 0;
> +	}
> +
> +	ret = spmi_ext_register_readl(pdev, reg,
> +				      (unsigned char *)&read_value, 1);
> +	if (ret) {
> +		pr_err("%s: spmi_ext_register_readl failed!\n", __func__);
> +		return 0;
> +	}
> +	return (u32)read_value;
> +}
> +EXPORT_SYMBOL(hi6421_spmi_pmic_read);
> +
> +void hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val)
> +{
> +	u32 ret;
> +	struct spmi_device *pdev;
> +
> +	pdev = to_spmi_device(pmic->dev);
> +	if (!pdev) {
> +		pr_err("%s: pdev get failed!\n", __func__);
> +		return;
> +	}
> +
> +	ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1);
> +	if (ret) {
> +		pr_err("%s: spmi_ext_register_writel failed!\n", __func__);
> +		return;
> +	}
> +}
> +EXPORT_SYMBOL(hi6421_spmi_pmic_write);
> +
> +void hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg,
> +			  u32 mask, u32 bits)
> +{
> +	u32 data;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&pmic->lock, flags);
> +	data = hi6421_spmi_pmic_read(pmic, reg) & ~mask;
> +	data |= mask & bits;
> +	hi6421_spmi_pmic_write(pmic, reg, data);
> +	spin_unlock_irqrestore(&pmic->lock, flags);
> +}
> +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 < pmic->irqarray; i++) {
> +		pending = hi6421_spmi_pmic_read(pmic, (i + pmic->irq_addr.start_addr));
> +		pending &= HISI_MASK_FIELD;
> +		if (pending != 0)
> +			pr_debug("pending[%d]=0x%lx\n\r", i, pending);
> +
> +		hi6421_spmi_pmic_write(pmic, (i + pmic->irq_addr.start_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 += pmic->irq_mask_addr.start_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 += pmic->irq_mask_addr.start_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 int get_pmic_device_tree_data(struct device_node *np,
> +				     struct hi6421_spmi_pmic *pmic)
> +{
> +	int ret = 0;

always set.

> +
> +	/*get pmic irq num*/
Comments are mostly fiarly obvious.
Also if there is one, why use an array read?

> +	ret = of_property_read_u32_array(np, "irq-num",
> +					 &pmic->irqnum, 1);
> +	if (ret) {
> +		pr_err("no irq-num property set\n");
> +		ret = -ENODEV;
> +		return ret;
> +	}
> +
> +	/*get pmic irq array number*/
> +	ret = of_property_read_u32_array(np, "irq-array",
> +					 &pmic->irqarray, 1);
> +	if (ret) {
> +		pr_err("no irq-array property set\n");
> +		ret = -ENODEV;
> +		return ret;
> +	}
> +
> +	/*SOC_PMIC_IRQ_MASK_0_ADDR*/
spacing in comments.

> +	ret = of_property_read_u32_array(np, "irq-mask-addr",
> +					 (int *)&pmic->irq_mask_addr, 2);
> +	if (ret) {
> +		pr_err("no irq-mask-addr property set\n");
> +		ret = -ENODEV;
> +		return ret;
> +	}
> +
> +	/*SOC_PMIC_IRQ0_ADDR*/

These superficially feel like things that would come from
the compatible, but maybe I'm missing something.

> +	ret = of_property_read_u32_array(np, "irq-addr",
> +					 (int *)&pmic->irq_addr, 2);

Unsurprisingly this takes a u32 * not a int *

> +	if (ret) {f_prop
> +		pr_err("no irq-addr property set\n");
> +		ret = -ENODEV;
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
> +{
> +	int i;
> +
> +	for (i = 0 ; i < pmic->irq_mask_addr.array; i++)
> +		hi6421_spmi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i,
> +				       HISI_MASK_STATE);
> +
> +	for (i = 0 ; i < pmic->irq_addr.array; i++) {
> +		unsigned int pending = hi6421_spmi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
> +
> +		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
> +			 pmic->irq_addr.start_addr + i, pending);
> +		hi6421_spmi_pmic_write(pmic, pmic->irq_addr.start_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 = NULL;
> +	enum of_gpio_flags flags;
> +	int ret = 0;
> +	int i;
> +	unsigned int virq;
> +
> +	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
> +	if (!pmic)
> +		return -ENOMEM;
> +
> +	/*TODO: get pmic dts info*/

Seems to be done?

> +	ret = get_pmic_device_tree_data(np, pmic);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Error reading hisi pmic dts\n");
> +		return ret;
> +	}
> +
> +	/* TODO: get and enable clk request */
> +	spin_lock_init(&pmic->lock);
> +
> +	pmic->dev = dev;
> +
> +	pmic->gpio = of_get_gpio_flags(np, 0, &flags);

Do we need flags for something?

Can we use the gpio/consumer.h interfaces for all this?

Though I'm not sure we need a gpio at all. Looks like we just
use it as an interrupt.  Get an interrupt directly instead.



> +	if (pmic->gpio < 0)
> +		return pmic->gpio;
> +
> +	if (!gpio_is_valid(pmic->gpio))
> +		return -EINVAL;
> +
> +	ret = gpio_request_one(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);
> +
> +	/* mask && clear IRQ status */
> +	hi6421_spmi_pmic_irq_prc(pmic);
> +
> +	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
> +	if (!pmic->irqs)
> +		goto irq_malloc;
> +
> +	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
> +					     &hi6421_spmi_domain_ops, pmic);
> +	if (!pmic->domain) {
> +		dev_err(dev, "failed irq domain add simple!\n");
> +		ret = -ENODEV;
> +		goto irq_domain;
> +	}
> +
> +	for (i = 0; i < pmic->irqnum; i++) {
> +		virq = irq_create_mapping(pmic->domain, i);
> +		if (virq == NO_IRQ) {
> +			pr_debug("Failed mapping hwirq\n");
> +			ret = -ENOSPC;
> +			goto irq_create_mapping;
> +		}
> +		pmic->irqs[i] = virq;
> +		pr_info("[%s]. pmic->irqs[%d] = %d\n", __func__, i, pmic->irqs[i]);

Noise

> +	}
> +
> +	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 %d\n", ret);
> +		ret = -ENODEV;
> +		goto request_theaded_irq;
> +	}
> +
> +	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);

This is mixing and matching managed an unmanaged. Should be one or the other
or we might be hiding some race conditions.


> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +
> +request_theaded_irq:
> +irq_create_mapping:
> +irq_domain:
> +irq_malloc:
> +	gpio_free(pmic->gpio);
> +	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);
> +	gpio_free(pmic->gpio);
> +	devm_kfree(&pdev->dev, pmic);

I hope that isn't needed!

> +}
> +
> +static const struct of_device_id pmic_spmi_id_table[] = {
> +	{ .compatible = "hisilicon,hi6421-spmi-pmic" },
> +	{ }
> +};
> +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/regulator/Kconfig b/drivers/regulator/Kconfig
> index edb1c4f8b496..de8a78487bb9 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -356,6 +356,14 @@ config REGULATOR_HI6421V530
>  	  provides 5 general purpose LDOs, and all of them come with support
>  	  to either ECO (idle) or sleep mode.
>  
> +config REGULATOR_HI6421V600
> +	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
> +	depends on MFD_HI6421_PMIC && OF

Can we do a COMPILE_TEST here?

> +	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_HI655X
>  	tristate "Hisilicon HI655X PMIC regulators support"
>  	depends on ARCH_HISI || COMPILE_TEST
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 0796e4a47afa..f59d5e3b5fd4 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.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..c80dfac1e4c3
> --- /dev/null
> +++ b/drivers/regulator/hi6421v600-regulator.c
> @@ -0,0 +1,493 @@
> +// 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.

Need to remove license text as have SPDX.

Blank line doesn't add anything here.


> + *
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_address.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/of_regulator.h>
> +#include <linux/mfd/hi6421-spmi-pmic.h>
> +#include <linux/delay.h>
> +#include <linux/time.h>
> +#include <linux/version.h>
> +#include <linux/seq_file.h>
> +#include <linux/uaccess.h>
> +#include <linux/spmi.h>
> +
> +#define rdev_dbg(rdev, fmt, arg...)	\
> +		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)

Not worth defining in my view.

> +
> +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)
> +{
> +	u32 reg_val;
> +	struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev);
> +	struct hi6421_spmi_pmic *pmic = sreg->pmic;
> +
> +	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;
> +
> +	/* unlikely to happen. sanity test done by regulator core */

Unlikely or can't?

> +	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;
> +	u32 reg_val;
> +	unsigned int mode;
> +
> +	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)) {
> +		rdev_dbg(rdev, "normal mode");

Debug seems unnecessary to me, but maybe keep it if you want.

> +		return REGULATOR_MODE_NORMAL;
> +	} else {
> +		rdev_dbg(rdev, "idle mode");
> +		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\nn");
> +		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);

one line.

> +		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",
> +		rdesc->vsel_reg, rdesc->vsel_mask);
> +
> +	return 0;
> +}
> +
> +static 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,
> +};
> +
> +/*
> + * Used only for parsing the DT properties
Odd comment. Clearly does more than that.

> + */
> +
> +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev,
> +					   struct device_node *np,
> +					   struct hi6421_spmi_pmic *pmic)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regulator_desc *rdesc;
> +	struct regulator_dev *rdev;
> +	struct hi6421v600_regulator *sreg = NULL;

Always set.

> +	struct regulator_init_data *initdata;
> +	struct regulator_config config = { };
> +	struct regulation_constraints *constraint;
> +	const char *supplyname = NULL;
> +	int ret = 0;

Always set I think

> +
> +	initdata = of_get_regulator_init_data(dev, np, NULL);
> +	if (!initdata) {
> +		dev_err(dev, "failed to get regulator data\n");
> +		return -EINVAL;
> +	}
> +
> +	sreg = kzalloc(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)
> +		goto probe_end;
> +
> +	/* 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);
> +		ret = PTR_ERR(rdev);
> +		goto probe_end;
> +	}
> +
> +	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);
I'd do separate error path.

	return 0;

> +probe_end:
> +	if (ret)

ret is set if separate error path.
I haven't figured out lifetime but can we not use devm for sreg?

> +		kfree(sreg);
> +	return ret;
> +}
> +
> +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;
> +
> +	dev_dbg(&pdev->dev, "probing hi6421v600 regulator\n");

Noise.

> +	/*
> +	 * 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);
> +
> +	/* TODO: should i worry about that? devm_kzalloc */

Answer that TODO.  No unless something odd going on.

> +	if (rdev->desc->volt_table)
> +		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
> +
> +	kfree(sreg);

This is a worrying mix of devm and not.  Never a good sign.
Lifetime of sreg seems strange.

> +
> +	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/spmi/Kconfig b/drivers/spmi/Kconfig
> index a53bad541f1a..b44e2ab6bf81 100644
> --- a/drivers/spmi/Kconfig
> +++ b/drivers/spmi/Kconfig
> @@ -25,4 +25,13 @@ config SPMI_MSM_PMIC_ARB
>  	  This is required for communicating with Qualcomm PMICs and
>  	  other devices that have the SPMI interface.
>  
> +config SPMI_HISI3670
> +	tristate "Hisilicon 3670 SPMI Controller"
> +	select IRQ_DOMAIN_HIERARCHY
> +	depends on HAS_IOMEM

I have a vague recollection some magic was done to mean we don't need that
any more (stubs for the few cases where it doesn't exist).
Could have remembered wrong though.

> +	help
> +	  If you say yes to this option, support will be included for the
> +	  built-in SPMI PMIC Arbiter interface on Hisilicon 3670
> +	  processors.
> +
>  endif
> diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
> index 55a94cadeffe..694853e391cb 100644
> --- a/drivers/spmi/Makefile
> +++ b/drivers/spmi/Makefile
> @@ -5,3 +5,5 @@
>  obj-$(CONFIG_SPMI)	+= spmi.o
>  
>  obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
> +
> +obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
> diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
> new file mode 100644
> index 000000000000..153bcdb0cde4
> --- /dev/null
> +++ b/drivers/spmi/hisi-spmi-controller.c
> @@ -0,0 +1,384 @@
> +// SPDX-License-Identifier: GPL-2.0
> +

I don't know much about spmi so this is very much a drive by review.

> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/seq_file.h>
> +#include <linux/spmi.h>

Nice to do alphabetical if no reason to do otherwise.

> +
> +#define SPMI_CONTROLLER_NAME		"spmi_controller"

Feels like we should have hisi in there.
Also should prefix naming throughout with HISI_SPMI

> +
> +/*
> + * 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
> +
> +/*

Nice to make this both correct kernel doc and reflect the
structure I assume it is documenting.

> + * @base base address of the PMIC Arbiter core registers.
> + * @rdbase, @wrbase base address of the PMIC Arbiter read core registers.
> + *     For HW-v1 these are equal to base.
> + *     For HW-v2, the value is the same in eeraly probing, in order to read
> + *     PMIC_ARB_CORE registers, then chnls, and obsrvr are set to
> + *     PMIC_ARB_CORE_REGISTERS and PMIC_ARB_CORE_REGISTERS_OBS respectivly.
> + * @intr base address of the SPMI interrupt control registers
> + * @ppid_2_chnl_tbl lookup table f(SID, Periph-ID) -> channel num
> + *      entry is only valid if corresponding bit is set in valid_ppid_bitmap.
> + * @valid_ppid_bitmap bit is set only for valid ppids.
> + * @fmt_cmd formats a command to be set into PMIC_ARBq_CHNLn_CMD
> + * @chnl_ofst calculates offset of the base of a channel reg space
> + * @ee execution environment id
> + * @irq_acc0_init_val initial value of the interrupt accumulator at probe time.
> + *      Use for an HW workaround. On handling interrupts, the first accumulator
> + *      register will be compared against this value, and bits which are set at
> + *      boot will be ignored.
> + * @reserved_chnl entry of ppid_2_chnl_tbl that this driver should never touch.
> + *      value is positive channel number or negative to mark it unused.
> + */
> +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 status = 0;

always set.

> +	u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
> +	u32 offset;
> +
> +	offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
> +	offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
> +
> +	while (timeout--) {
> +		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);
> +	}
> +
> +	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 sid, u16 addr, u8 *__buf, size_t bc)
> +{

Same stuff as for the write below.

> +	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> +	unsigned long flags;
> +	u8 *buf = __buf;
> +	u32 cmd, data;
> +	int rc;
> +	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> +	u8 op_code, i;
> +
> +	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> +		dev_err(&ctrl->dev,
> +			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
> +			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> +		return  -EINVAL;
> +	}
> +
> +	/* Check the opcode */
> +	if (opc == SPMI_CMD_READ) {
> +		op_code = SPMI_CMD_REG_READ;
> +	} else if (opc == SPMI_CMD_EXT_READ) {
> +		op_code = SPMI_CMD_EXT_REG_READ;
> +	} else if (opc == SPMI_CMD_EXT_READL) {
> +		op_code = SPMI_CMD_EXT_REG_READ_L;
> +	} else {
> +		dev_err(&ctrl->dev, "invalid read cmd 0x%x", 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) |
> +	     ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
> +	     ((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, sid, addr);
> +	if (rc)
> +		goto done;
> +
> +	i = 0;
> +	do {
> +		data = readl(spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET * sid + 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);
> +		}
> +		i++;
> +	} while (bc > i * 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 sid:%d addr:0x%x bc:%ld\n",
> +			opc, sid, addr, bc + 1);
> +	else
> +		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
> +			__func__, sid, addr, (int)bc, __buf);
> +
> +	return rc;
> +}
> +
> +static int spmi_write_cmd(struct spmi_controller *ctrl,
> +			  u8 opc, u8 sid, u16 addr, const u8 *__buf, size_t bc)
> +{
> +	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> +	const u8 *buf = __buf;
> +	unsigned long flags;
> +	u32 cmd, data;
> +	int rc;
> +	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> +	u8 op_code, i;
> +
> +	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> +		dev_err(&ctrl->dev,
> +			"spmi_controller supports 1..%d bytes per trans, but:%ld requested",
> +			SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> +		return  -EINVAL;
> +	}
> +
> +	/* Check the opcode */

Kind of obvious given the code :)

> +	if (opc == SPMI_CMD_WRITE) {
> +		op_code = SPMI_CMD_REG_WRITE;
> +	} else if (opc == SPMI_CMD_EXT_WRITE) {
> +		op_code = SPMI_CMD_EXT_REG_WRITE;
> +	} else if (opc == SPMI_CMD_EXT_WRITEL) {
> +		op_code = SPMI_CMD_EXT_REG_WRITE_L;

Looks like something better expressed as a switch statement to me.

> +	} else {
> +		dev_err(&ctrl->dev, "invalid write cmd 0x%x", 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) |
> +	      ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
> +	      ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
Those two comments pretty clearly highlight that names of variables could
be better.

could we use FIELD_PREP and friends to do this more neatly?

> +
> +	/* Write data to FIFOs */
> +	spin_lock_irqsave(&spmi_controller->lock, flags);
> +
> +	i = 0;
> +	do {
> +		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);
> +		i++;
> +	} while (bc > i * SPMI_PER_DATAREG_BYTE);
> +
> +	/* 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, sid, addr);
> +	spin_unlock_irqrestore(&spmi_controller->lock, flags);
> +
> +	if (rc)
> +		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
> +			opc, sid, addr, bc);
> +	else
> +		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
> +			__func__, sid, addr, (int)bc, __buf);

I'd drop the debug.  Adds a lot of code for limited benefit.

> +
> +	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 = 0;
Fairly sure that's set in all paths.

> +
> +	dev_info(&pdev->dev, "HISI SPMI probe\n");

Too noisy

> +
> +	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));

We don't seem to clean this up in failure paths.

> +	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;
> +
> +	/* NOTE: driver uses the static register mapping */

Do we need to Note it for some reason I'm not seeing?

> +	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!iores) {
> +		dev_err(&pdev->dev, "can not get resource!\n");
> +		return -EINVAL;
> +	}
> +
> +	spmi_controller->base = ioremap(iores->start, resource_size(iores));
> +	if (!spmi_controller->base) {
> +		dev_err(&pdev->dev, "can not remap base addr!\n");
> +		return -EADDRNOTAVAIL;
> +	}
> +	dev_dbg(&pdev->dev, "spmi_add_controller base addr=0x%lx!\n",
> +		(unsigned long)spmi_controller->base);

I doubt that one is ever of any use to anyone after initial driver
writing. I'd drop it.

> +
> +	/* Get properties from the device tree */

Comment doesn't add anything

> +	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)
> +		goto err_add_controller;
> +
> +	dev_info(&pdev->dev, "spmi_add_controller initialized\n");

Too noisy.

> +	return 0;
> +
> +err_add_controller:
> +	dev_err(&pdev->dev, "spmi_add_controller failed!\n");

Seems too noisy to me given information provided is minimal.


> +	platform_set_drvdata(pdev, NULL);

not needed.

> +	return ret;
Use direct returns if not cleaning anything up... THough see above,
there are things that I'm fairly sure you should be!

> +}
> +
> +static int spmi_del_controller(struct platform_device *pdev)
> +{
> +	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
> +
> +	platform_set_drvdata(pdev, NULL);

Doubt you need that. Core sets it to null on remove or error.

> +	spmi_controller_remove(ctrl);

It's asking for a devm_spmi_controller_add.  or just go
with devm_add_action_or_reset perhaps.


> +	return 0;
> +}
> +
> +static const struct of_device_id spmi_controller_match_table[] = {
> +	{	.compatible = "hisilicon,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	= SPMI_CONTROLLER_NAME,
> +		.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_controlller");
> diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> index c16b60f645a4..253340e10dab 100644
> --- a/drivers/spmi/spmi.c
> +++ b/drivers/spmi/spmi.c

All the changes in here look to be cleanup.  Drop it from this series
as it just adds noise.
> @@ -23,6 +23,7 @@ static DEFINE_IDA(ctrl_ida);
>  static void spmi_dev_release(struct device *dev)
>  {
>  	struct spmi_device *sdev = to_spmi_device(dev);
> +
>  	kfree(sdev);
>  }
>  
> @@ -33,6 +34,7 @@ static const struct device_type spmi_dev_type = {
>  static void spmi_ctrl_release(struct device *dev)
>  {
>  	struct spmi_controller *ctrl = to_spmi_controller(dev);
> +
>  	ida_simple_remove(&ctrl_ida, ctrl->nr);
>  	kfree(ctrl);
>  }
> @@ -487,7 +489,7 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl)
>  			continue;
>  
>  		sdev->dev.of_node = node;
> -		sdev->usid = (u8) reg[0];
> +		sdev->usid = (u8)reg[0];
>  
>  		err = spmi_device_add(sdev);
>  		if (err) {
> @@ -531,6 +533,7 @@ EXPORT_SYMBOL_GPL(spmi_controller_add);
>  static int spmi_ctrl_remove_device(struct device *dev, void *data)
>  {
>  	struct spmi_device *spmidev = to_spmi_device(dev);
> +
>  	if (dev->type == &spmi_dev_type)
>  		spmi_device_remove(spmidev);
>  	return 0;
> @@ -545,13 +548,10 @@ static int spmi_ctrl_remove_device(struct device *dev, void *data)
>   */
>  void spmi_controller_remove(struct spmi_controller *ctrl)
>  {
> -	int dummy;
> -
>  	if (!ctrl)
>  		return;
>  
> -	dummy = device_for_each_child(&ctrl->dev, NULL,
> -				      spmi_ctrl_remove_device);
> +	device_for_each_child(&ctrl->dev, NULL, spmi_ctrl_remove_device);
>  	device_del(&ctrl->dev);
>  }
>  EXPORT_SYMBOL_GPL(spmi_controller_remove);




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

* Re: [PATCH 14/33] spmi: add hisi-spmi-controller to the building system
  2020-08-11 15:41 ` [PATCH 14/33] spmi: add hisi-spmi-controller to the building system Mauro Carvalho Chehab
@ 2020-08-11 20:53   ` kernel test robot
  0 siblings, 0 replies; 48+ messages in thread
From: kernel test robot @ 2020-08-11 20:53 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: kbuild-all, linux-media, linuxarm, mauro.chehab,
	Mauro Carvalho Chehab, Stephen Boyd, linux-arm-msm, linux-kernel

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

Hi Mauro,

I love your patch! Perhaps something to improve:

[auto build test WARNING on lee-mfd/for-mfd-next]
[also build test WARNING on regulator/for-next robh/for-next linus/master v5.8 next-20200811]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Mauro-Carvalho-Chehab/Add-driver-for-HiSilicon-SPMI-PMIC-for-Hikey-970/20200811-234737
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: arc-allyesconfig (attached as .config)
compiler: arc-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/spmi/hisi-spmi-controller.c:7:
   drivers/spmi/hisi-spmi-controller.c: In function 'spmi_read_cmd':
>> drivers/spmi/hisi-spmi-controller.c:149:5: warning: format '%ld' expects argument of type 'long int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
     149 |   , "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/spmi/hisi-spmi-controller.c:148:3: note: in expansion of macro 'dev_err'
     148 |   dev_err(spmi_controller->dev
         |   ^~~~~~~
   drivers/spmi/hisi-spmi-controller.c:149:60: note: format string is defined here
     149 |   , "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
         |                                                          ~~^
         |                                                            |
         |                                                            long int
         |                                                          %d
   In file included from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/spmi/hisi-spmi-controller.c:7:
   drivers/spmi/hisi-spmi-controller.c:198:33: warning: format '%ld' expects argument of type 'long int', but argument 6 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
     198 |   dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/spmi/hisi-spmi-controller.c:198:3: note: in expansion of macro 'dev_err'
     198 |   dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |   ^~~~~~~
   drivers/spmi/hisi-spmi-controller.c:198:87: note: format string is defined here
     198 |   dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |                                                                                     ~~^
         |                                                                                       |
         |                                                                                       long int
         |                                                                                     %d
   In file included from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/spmi/hisi-spmi-controller.c:7:
   drivers/spmi/hisi-spmi-controller.c: In function 'spmi_write_cmd':
   drivers/spmi/hisi-spmi-controller.c:220:5: warning: format '%ld' expects argument of type 'long int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
     220 |   , "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/spmi/hisi-spmi-controller.c:219:3: note: in expansion of macro 'dev_err'
     219 |   dev_err(spmi_controller->dev
         |   ^~~~~~~
   drivers/spmi/hisi-spmi-controller.c:220:60: note: format string is defined here
     220 |   , "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
         |                                                          ~~^
         |                                                            |
         |                                                            long int
         |                                                          %d
   In file included from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from drivers/spmi/hisi-spmi-controller.c:7:
   drivers/spmi/hisi-spmi-controller.c:269:33: warning: format '%ld' expects argument of type 'long int', but argument 6 has type 'size_t' {aka 'unsigned int'} [-Wformat=]
     269 |   dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/spmi/hisi-spmi-controller.c:269:3: note: in expansion of macro 'dev_err'
     269 |   dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |   ^~~~~~~
   drivers/spmi/hisi-spmi-controller.c:269:88: note: format string is defined here
     269 |   dev_err(spmi_controller->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
         |                                                                                      ~~^
         |                                                                                        |
         |                                                                                        long int
         |                                                                                      %d

vim +149 drivers/spmi/hisi-spmi-controller.c

3f5f1801bf6c4a3 Mayulong              2020-08-11  135  
3f5f1801bf6c4a3 Mayulong              2020-08-11  136  static int spmi_read_cmd(struct spmi_controller *ctrl,
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  137  			 u8 opc, u8 sid, u16 addr, u8 *__buf, size_t bc)
3f5f1801bf6c4a3 Mayulong              2020-08-11  138  {
3f5f1801bf6c4a3 Mayulong              2020-08-11  139  	struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
3f5f1801bf6c4a3 Mayulong              2020-08-11  140  	unsigned long flags;
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  141  	u8 *buf = __buf;
3f5f1801bf6c4a3 Mayulong              2020-08-11  142  	u32 cmd, data;
3f5f1801bf6c4a3 Mayulong              2020-08-11  143  	int rc;
3f5f1801bf6c4a3 Mayulong              2020-08-11  144  	u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
3f5f1801bf6c4a3 Mayulong              2020-08-11  145  	u8 op_code, i;
3f5f1801bf6c4a3 Mayulong              2020-08-11  146  
3f5f1801bf6c4a3 Mayulong              2020-08-11  147  	if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
3f5f1801bf6c4a3 Mayulong              2020-08-11  148  		dev_err(spmi_controller->dev
3f5f1801bf6c4a3 Mayulong              2020-08-11 @149  		, "spmi_controller supports 1..%d bytes per trans, but:%ld requested"
3f5f1801bf6c4a3 Mayulong              2020-08-11  150  					, SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
3f5f1801bf6c4a3 Mayulong              2020-08-11  151  		return  -EINVAL;
3f5f1801bf6c4a3 Mayulong              2020-08-11  152  	}
3f5f1801bf6c4a3 Mayulong              2020-08-11  153  
3f5f1801bf6c4a3 Mayulong              2020-08-11  154  	/* Check the opcode */
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  155  	if (opc == SPMI_CMD_READ) {
3f5f1801bf6c4a3 Mayulong              2020-08-11  156  		op_code = SPMI_CMD_REG_READ;
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  157  	} else if (opc == SPMI_CMD_EXT_READ) {
3f5f1801bf6c4a3 Mayulong              2020-08-11  158  		op_code = SPMI_CMD_EXT_REG_READ;
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  159  	} else if (opc == SPMI_CMD_EXT_READL) {
3f5f1801bf6c4a3 Mayulong              2020-08-11  160  		op_code = SPMI_CMD_EXT_REG_READ_L;
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  161  	} else {
3f5f1801bf6c4a3 Mayulong              2020-08-11  162  		dev_err(spmi_controller->dev, "invalid read cmd 0x%x", opc);
3f5f1801bf6c4a3 Mayulong              2020-08-11  163  		return -EINVAL;
3f5f1801bf6c4a3 Mayulong              2020-08-11  164  	}
3f5f1801bf6c4a3 Mayulong              2020-08-11  165  
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  166  	cmd = SPMI_APB_SPMI_CMD_EN |
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  167  	     (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  168  	     ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
3f5f1801bf6c4a3 Mayulong              2020-08-11  169  	     ((sid & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
3f5f1801bf6c4a3 Mayulong              2020-08-11  170  	     ((addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
3f5f1801bf6c4a3 Mayulong              2020-08-11  171  
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  172  	spin_lock_irqsave(&spmi_controller->lock, flags);
3f5f1801bf6c4a3 Mayulong              2020-08-11  173  
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  174  	writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
3f5f1801bf6c4a3 Mayulong              2020-08-11  175  
afd5339d05a6fd2 Mauro Carvalho Chehab 2020-08-11  176  	rc = spmi_controller_wait_for_done(spmi_controller,
afd5339d05a6fd2 Mauro Carvalho Chehab 2020-08-11  177  					   spmi_controller->base, sid, addr);
3f5f1801bf6c4a3 Mayulong              2020-08-11  178  	if (rc)
3f5f1801bf6c4a3 Mayulong              2020-08-11  179  		goto done;
3f5f1801bf6c4a3 Mayulong              2020-08-11  180  
3f5f1801bf6c4a3 Mayulong              2020-08-11  181  	i = 0;
3f5f1801bf6c4a3 Mayulong              2020-08-11  182  	do {
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  183  		data = readl(spmi_controller->base + chnl_ofst + SPMI_SLAVE_OFFSET * sid + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i * SPMI_PER_DATAREG_BYTE);
afd5339d05a6fd2 Mauro Carvalho Chehab 2020-08-11  184  		data = be32_to_cpu((__be32)data);
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  185  		if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
3f5f1801bf6c4a3 Mayulong              2020-08-11  186  			memcpy(buf, &data, sizeof(data));
3f5f1801bf6c4a3 Mayulong              2020-08-11  187  			buf += sizeof(data);
3f5f1801bf6c4a3 Mayulong              2020-08-11  188  		} else {
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  189  			memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
3f5f1801bf6c4a3 Mayulong              2020-08-11  190  			buf += (bc % SPMI_PER_DATAREG_BYTE);
3f5f1801bf6c4a3 Mayulong              2020-08-11  191  		}
3f5f1801bf6c4a3 Mayulong              2020-08-11  192  		i++;
3f5f1801bf6c4a3 Mayulong              2020-08-11  193  	} while (bc > i * SPMI_PER_DATAREG_BYTE);
3f5f1801bf6c4a3 Mayulong              2020-08-11  194  
3f5f1801bf6c4a3 Mayulong              2020-08-11  195  done:
3f5f1801bf6c4a3 Mayulong              2020-08-11  196  	spin_unlock_irqrestore(&spmi_controller->lock, flags);
3f5f1801bf6c4a3 Mayulong              2020-08-11  197  	if (rc)
3f5f1801bf6c4a3 Mayulong              2020-08-11  198  		dev_err(spmi_controller->dev, "spmi read wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
3f5f1801bf6c4a3 Mayulong              2020-08-11  199  			opc, sid, addr, bc + 1);
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  200  	else
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  201  		dev_dbg(spmi_controller->dev, "%s: id:%d addr:0x%x, read value: %*ph\n",
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  202  			__func__, sid, addr, (int)bc, __buf);
a93f9ffda101599 Mauro Carvalho Chehab 2020-08-11  203  
3f5f1801bf6c4a3 Mayulong              2020-08-11  204  	return rc;
43091a1c2b8d45e Mauro Carvalho Chehab 2020-08-11  205  }
3f5f1801bf6c4a3 Mayulong              2020-08-11  206  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 64660 bytes --]

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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-11 17:51   ` Jonathan Cameron
@ 2020-08-12  7:45     ` Mauro Carvalho Chehab
  2020-08-12  8:43       ` Jonathan Cameron
  0 siblings, 1 reply; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-12  7:45 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Rob Herring, linux-kernel, devicetree, Stephen Boyd,
	linux-arm-msm, Mark Brown, Mayulong, linuxarm, Liam Girdwood,
	Rob Herring, Lee Jones, David S. Miller, linux-arm-kernel

Em Tue, 11 Aug 2020 18:51:11 +0100
Jonathan Cameron <Jonathan.Cameron@Huawei.com> escreveu:

> On Tue, 11 Aug 2020 17:54:29 +0200
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:
> 
> > Em Tue, 11 Aug 2020 17:41:26 +0200
> > Mauro Carvalho Chehab <mchehab+huawei@kernel.org> escreveu:
> >   
> > > The Hikey 970 board uses a different PMIC than the one found on Hikey 960.
> > > 
> > > This PMIC uses a SPMI board.
> > > 
> > > This patch series backport the OOT drivers from the Linaro's official
> > > tree for this board:
> > > 
> > > 	https://github.com/96boards-hikey/linux/tree/hikey970-v4.9
> > > 	
> > > Porting them to upstream, cleaning up coding style issues, solving
> > > driver probing order and adding DT documentation.
> > > 
> > > I opted to not fold all patches into a single one, in order to:
> > > 
> > > - Preserve the authorship of the original authors;
> > > - Keep a history of changes.
> > > 
> > > As this could be harder for people to review, I'll be replying to patch 00/32
> > > with all patches folded. This should help reviewers to see the current
> > > code after the entire series is applied.    
> > 
> > As promised, it follows the diff from this entire patch series.
> > 
> > Feel free to review either on the top of this e-mail or on the
> > individual patches.
> >   
> 
> Whilst I agree entirely with Mark about the need to turn this into a clean series,
> I was bored at the end of the day so here is a drive by review..

Thanks for the review!

> I've not looked at anything that really needed any thought as it is too hot for
> thinking.

8-)

> > 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..33dcbaeb474e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml

...

> > +        $ref: "/schemas/regulator/regulator.yaml#"
> > +
> > +        properties:
> > +          reg:
> > +            description: Enable register.
> > +
> > +          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  
> 
> Guess this needs fixing up.

Ah, yeah. Thanks for noticing. I had some troubles with dtbs_check, so
I ended commenting out some things for testing purposes. I'll remove the
comments and check if this was already solved with the current schema.

> > @@ -39,7 +40,7 @@ memory@0 {
> >  		reg = <0x0 0x0 0x0 0x0>;
> >  	};
> >  
> > -	sd_1v8: regulator-1v8 {
> > +	fixed_1v8: regulator-1v8 {  
> 
> Rename relevant?

I guess I can do the rename to a different patch - or maybe even better - drop
this regulator on this series and re-add with a different name on
some other patch.

The thing is that this regulator is currently used by the SDIO device
drivers. That's the reason why it starts with "sd_". 

However, at the real hardware, there are 3 different regulator outputs 
for SDIO related stuff. Such change is inside this patchset.

However, there is the need of a 1v8 fixed power line used on another 
upcoming driver. I guess I was too lazy to keep the DT info here ;-)

> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index a37d7d171382..04c249649532 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -493,10 +493,25 @@ config MFD_HI6421_PMIC
> >  	  Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi-
> >  	  functions, such as regulators, RTC, codec, Coulomb counter, etc.
> >  	  This driver includes core APIs _only_. You have to select
> > -	  individul components like voltage regulators under corresponding
> > +	  individual components like voltage regulators under corresponding  
> 
> Don't fix other drivers.

This is actually on an independent patch:

	https://lore.kernel.org/lkml/176043f329dfa9889f014feec04e7e1553077873.1597160086.git.mchehab+huawei@kernel.org/T/#m1864011fa82154c6aa27fd4b2e9fce396bb3cd33

I guess I'll just submit this specific one outside this series.

> 
> >  	  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
> > +	select MFD_CORE
> > +	select REGMAP_MMIO  
> 
> Nice thought, but it doesn't use it yet!

What do you mean? Makefile should be using it:

	$ git grep MFD_HI6421_SPMI
	drivers/mfd/Kconfig:config MFD_HI6421_SPMI
	drivers/mfd/Makefile:obj-$(CONFIG_MFD_HI6421_SPMI)      += hi6421-spmi-pmic.o


> > + *
> > + */
> > +
> > +#include <linux/slab.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/module.h>
> > +#include <linux/err.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_gpio.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/mfd/hi6421-spmi-pmic.h>
> > +#include <linux/irq.h>
> > +#include <linux/spmi.h>
> > +#ifndef NO_IRQ
> > +#define NO_IRQ       0  
> 
> Drop

Ok! I was in doubt about that, as there are a few other drivers with
the same pattern:

	drivers/ata/sata_dwc_460ex.c:#define NO_IRQ             0
	drivers/input/touchscreen/ucb1400_ts.c:#define NO_IRQ   0
	drivers/mmc/host/of_mmc_spi.c:#define NO_IRQ 0
	drivers/pcmcia/pd6729.c:#define NO_IRQ  ((unsigned int)(0))
	drivers/rtc/rtc-m48t59.c:#define NO_IRQ (-1)

Btw, this definition at the rtc driver sounds weird ;-)
 
> > +
> > +/*
> > + * 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.  

> Can we return the 8 bits in an int and hence also return error codes?
> > + */
> > +u32 hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg)

I'll change the driver to use "int" and return proper error codes on errors.

> > +
> > +static int get_pmic_device_tree_data(struct device_node *np,
> > +				     struct hi6421_spmi_pmic *pmic)
> > +{
> > +	int ret = 0;  
> 
> always set.
> 
> > +
> > +	/*get pmic irq num*/  
> Comments are mostly fiarly obvious.

Yep. I'll drop the obvious ones.

> Also if there is one, why use an array read?
> > +	ret = of_property_read_u32_array(np, "irq-num",
> > +					 &pmic->irqnum, 1);


Good point. I'll fix it.


> > +	/*SOC_PMIC_IRQ0_ADDR*/  
> 
> These superficially feel like things that would come from
> the compatible, but maybe I'm missing something.

My guess is that this is decided by the board manufacturer. I mean,
from the schematics:

	https://www.96boards.org/documentation/consumer/hikey/hikey970/hardware-docs/files/hikey970-schematics.pdf

This is a separate chipset, connected at the Kirin 970 SPMI bus. The SPMI bus
allows up to 16 PMICs. So, I would assume that a chip designed to support
SPMI would have the flexibility of using different IRQ lines, being
programmable either via some firmware or via some wiring.

Without knowing more, IMO the best would be to keep those settings
at DT.

> 
> > +	ret = of_property_read_u32_array(np, "irq-addr",
> > +					 (int *)&pmic->irq_addr, 2);  
> 
> Unsurprisingly this takes a u32 * not a int *

I'll remove the casting. Btw, I guess I'll even replace it by
a single number instead of an array, as the second value
is already at the "irq-array" DT property:

			irq-num = <16>;
			irq-array = <2>;
			irq-mask-addr = <0x202 2>;
			irq-addr = <0x212 2>;

The arrays for irq-mask-addr and irq-addr are:

	struct hi6421_spmi_irq_mask_info {
		int start_addr;
		int array;
	};

	struct hi6421_spmi_irq_info {
		int start_addr;
		int array;
	};

At the code, sometimes it uses irq_mask->array, while on others it
use irqarray, apparently for the same goal. So, it sounds safe to get
rid of the duplication there. I'll place this on a separate patch,
as I might have been missing something.

> 
> > +	if (ret) {f_prop
> > +		pr_err("no irq-addr property set\n");
> > +		ret = -ENODEV;
> > +		return ret;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
> > +{
> > +	int i;
> > +
> > +	for (i = 0 ; i < pmic->irq_mask_addr.array; i++)
> > +		hi6421_spmi_pmic_write(pmic, pmic->irq_mask_addr.start_addr + i,
> > +				       HISI_MASK_STATE);
> > +
> > +	for (i = 0 ; i < pmic->irq_addr.array; i++) {
> > +		unsigned int pending = hi6421_spmi_pmic_read(pmic, pmic->irq_addr.start_addr + i);
> > +
> > +		pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
> > +			 pmic->irq_addr.start_addr + i, pending);
> > +		hi6421_spmi_pmic_write(pmic, pmic->irq_addr.start_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 = NULL;
> > +	enum of_gpio_flags flags;
> > +	int ret = 0;
> > +	int i;
> > +	unsigned int virq;
> > +
> > +	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
> > +	if (!pmic)
> > +		return -ENOMEM;
> > +
> > +	/*TODO: get pmic dts info*/  
> 
> Seems to be done?

Sounds some obsolete comment. I'll drop it.

> 
> > +	ret = get_pmic_device_tree_data(np, pmic);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Error reading hisi pmic dts\n");
> > +		return ret;
> > +	}
> > +
> > +	/* TODO: get and enable clk request */
> > +	spin_lock_init(&pmic->lock);
> > +
> > +	pmic->dev = dev;
> > +
> > +	pmic->gpio = of_get_gpio_flags(np, 0, &flags);  
> 
> Do we need flags for something?
> 
> Can we use the gpio/consumer.h interfaces for all this?
> 
> Though I'm not sure we need a gpio at all. Looks like we just
> use it as an interrupt.  Get an interrupt directly instead.

Yeah, from what I saw, the GPIOs supported right now by this driver
are just for IRQs.

> > +	if (pmic->gpio < 0)
> > +		return pmic->gpio;
> > +
> > +	if (!gpio_is_valid(pmic->gpio))
> > +		return -EINVAL;
> > +
> > +	ret = gpio_request_one(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);
> > +
> > +	/* mask && clear IRQ status */
> > +	hi6421_spmi_pmic_irq_prc(pmic);
> > +
> > +	pmic->irqs = devm_kzalloc(dev, pmic->irqnum * sizeof(int), GFP_KERNEL);
> > +	if (!pmic->irqs)
> > +		goto irq_malloc;
> > +
> > +	pmic->domain = irq_domain_add_simple(np, pmic->irqnum, 0,
> > +					     &hi6421_spmi_domain_ops, pmic);
> > +	if (!pmic->domain) {
> > +		dev_err(dev, "failed irq domain add simple!\n");
> > +		ret = -ENODEV;
> > +		goto irq_domain;
> > +	}
> > +
> > +	for (i = 0; i < pmic->irqnum; i++) {
> > +		virq = irq_create_mapping(pmic->domain, i);
> > +		if (virq == NO_IRQ) {
> > +			pr_debug("Failed mapping hwirq\n");
> > +			ret = -ENOSPC;
> > +			goto irq_create_mapping;
> > +		}
> > +		pmic->irqs[i] = virq;
> > +		pr_info("[%s]. pmic->irqs[%d] = %d\n", __func__, i, pmic->irqs[i]);  
> 
> Noise

Yep. Will drop or convert into dev_dbg().

> 
> > +	}
> > +
> > +	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 %d\n", ret);
> > +		ret = -ENODEV;
> > +		goto request_theaded_irq;
> > +	}
> > +
> > +	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);  
> 
> This is mixing and matching managed an unmanaged. Should be one or the other
> or we might be hiding some race conditions.

Actually, it is just the opposite. It took me a lot of time to
figure out a good solution that will prevent all race conditions at
probe time.

See, the SPMI variant of HiSilicon 6421 requires the drivers to be
probed on a very specific order:

- The SPMI controller should be loaded first, as it provides 
  the low-level I/O access to the serial bus used to talk with the
  PMICs. This bus is somewhat similar to the I2C bus.

  Once the controller is registered, the SPMI bus probes the PMIC
  driver.

- Then, the MFD PMIC driver should be loaded. This adds support for
  a high level set of I/O operations, which are used by the regulator
  driver. Again, this approach is similar to the one taken by the
  I2C Kernel drivers.

- Finally, the regulator drivers should come, as they rely on the
  MFD I/O operations in order to talk with the SPMI bus.

The OOT driver probing was based on a some dirty hacks: it had an
empty SPMI entry at the SoC, carrying on just the "compatible" line.

Then, another entry at DT with the real SPMI settings.

With such dirty hack, on Kernel 4.9, the PMIC driver were always 
loading before the regulator ones, as the SPMI bus code were 
serializing the probe there.

However, such settings were too fragile and broke after porting to
upstream Kernels, because the regulator drivers were probed on
a random order, typically before the MFD one (and sometimes even 
before the SPMI controller driver). Adding EPROBE_DEFER didn't
solve all the issues, and made a complex and hard to debug scenario.
Also, regulators were probed on a random order, making harder to
debug issues there.

So, I ended using the same solution used by the already-existing
drivers/mfd/hi6421-pmic-core.c driver[1].

[1] This variant of the 6421 chipset is a lot simpler, as it
    doesn't use the SPMI bus.

With such approach, the probing is warranted to happen the
way it is expected by the driver:

SPMI controller code starts:
	[    0.416862] spmi_controller fff24000.spmi: HISI SPMI probe
	[    0.422419] spmi spmi-0: allocated controller 0x(____ptrval____) id 0
	[    0.428929] spmi_controller fff24000.spmi: spmi_add_controller base addr=0xffff800012055000!
	[    0.437480] spmi spmi-0: adding child /spmi@fff24000/pmic@0
	[    0.443109] spmi spmi-0: read usid 00
	[    0.446821] spmi 2-00: device 2-00 registered
	[    0.451220] spmi spmi-0: spmi-2 registered: dev:(____ptrval____)
	[    0.457286] spmi_controller fff24000.spmi: spmi_add_controller initialized

The PMIC probe happens sometime after spmi_controller registers itself
at the SPMI bus:

	[    1.955838] [hi6421_spmi_pmic_probe]. pmic->irqs[0] = 43
...
	[    2.036298] [hi6421_spmi_pmic_probe]. pmic->irqs[15] = 58

After being ready to handle I/O requests, it starts probing the
regulators:

	[    2.057815] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo3@16
	[    2.199827] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo4@17
	[    2.336284] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo9@1C
	[    2.472675] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo15@21
	[    2.609402] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo16@22
	[    2.746378] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo17@23
	[    2.846707] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo33@32
	[    2.988646] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo34@33

As the current code serializes the regulator probing, it ensured that
they'll happen at the right order, avoiding race conditions at
probe time.

> 
> 
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "Failed to add child devices: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +
> > +request_theaded_irq:
> > +irq_create_mapping:
> > +irq_domain:
> > +irq_malloc:
> > +	gpio_free(pmic->gpio);
> > +	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);
> > +	gpio_free(pmic->gpio);
> > +	devm_kfree(&pdev->dev, pmic);  
> 
> I hope that isn't needed!

Yeah, we can get rid of devm_kfree().

> 
> > +}
> > +
> > +static const struct of_device_id pmic_spmi_id_table[] = {
> > +	{ .compatible = "hisilicon,hi6421-spmi-pmic" },
> > +	{ }
> > +};
> > +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/regulator/Kconfig b/drivers/regulator/Kconfig
> > index edb1c4f8b496..de8a78487bb9 100644
> > --- a/drivers/regulator/Kconfig
> > +++ b/drivers/regulator/Kconfig
> > @@ -356,6 +356,14 @@ config REGULATOR_HI6421V530
> >  	  provides 5 general purpose LDOs, and all of them come with support
> >  	  to either ECO (idle) or sleep mode.
> >  
> > +config REGULATOR_HI6421V600
> > +	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
> > +	depends on MFD_HI6421_PMIC && OF  
> 
> Can we do a COMPILE_TEST here?

Neither REGULATOR_HI6421V600 nor MFD_HI6421_PMIC depends on ARM or
ARM64, so they should build fine on any arch. So, I'm failing to see
why adding COMPILE_TEST would make any difference.

> > +
> > +#include <linux/slab.h>
> > +#include <linux/device.h>
> > +#include <linux/module.h>
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_address.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/driver.h>
> > +#include <linux/regulator/machine.h>
> > +#include <linux/regulator/of_regulator.h>
> > +#include <linux/mfd/hi6421-spmi-pmic.h>
> > +#include <linux/delay.h>
> > +#include <linux/time.h>
> > +#include <linux/version.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/spmi.h>
> > +
> > +#define rdev_dbg(rdev, fmt, arg...)	\
> > +		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)  
> 
> Not worth defining in my view.

That was my first approach: to drop any existing printk macro, replacing
them by dev_dbg(). However, with dev_dbg(), the logs were like:

[    2.069301] platform ldo3: LDO doesn't support economy mode.
[    2.074969] platform ldo3: voltage selector settings: reg: 0x51, mask: 0xf
[    2.094593] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.105530] regulator.3: hi6421_spmi_regulator_enable: off_on_delay=20000 us, enable_reg=0x16, enable_mask=0x1
[    2.153484] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.163409] ldo3: 1500 <--> 2000 mV at 1800 mV normal 
[    2.181305] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.191289] regulator.3: hi6421_spmi_regulator_probe_ldo: valid_modes_mask: 0x2, valid_ops_mask: 0x9

E. g. the messages printed by the regulator's core were using 
(rdev)->desc->name on their printks, producing a nice debug
(when enabled at core level), while dev_dbg() were using a different name.

In this specific case, one might assume that "regulator.3" is "ldo3",
but this is by coincidence, as it actually matches the sysfs entries:

	$ ls -l /sys/class/regulator/
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.0 -> ../../devices/platform/reg-dummy/regulator/regulator.0
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.1 -> ../../devices/platform/regulator-1v8/regulator/regulator.1
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.10 -> ../../devices/platform/spmi-0/2-00/ldo34/regulator/regulator.10
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.2 -> ../../devices/platform/wlan-en-1-8v/regulator/regulator.2
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.3 -> ../../devices/platform/spmi-0/2-00/ldo3/regulator/regulator.3
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.4 -> ../../devices/platform/spmi-0/2-00/ldo4/regulator/regulator.4
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.5 -> ../../devices/platform/spmi-0/2-00/ldo9/regulator/regulator.5
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.6 -> ../../devices/platform/spmi-0/2-00/ldo15/regulator/regulator.6
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.7 -> ../../devices/platform/spmi-0/2-00/ldo16/regulator/regulator.7
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.8 -> ../../devices/platform/spmi-0/2-00/ldo17/regulator/regulator.8
	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.9 -> ../../devices/platform/spmi-0/2-00/ldo33/regulator/regulator.9

When playing with DT, the "regulator.[\d+]" namespace may change,
making harder to debug stuff. So, basically, enabling just the logs
at the regulator driver were requiring to double-check the sysfs 
entries in order to see what "regulator.3" were actually meaning
with a particular DT setting.

After adding the macro, the output is a lot easier to be understood:

[    2.069301] platform ldo3: LDO doesn't support economy mode.
[    2.074969] platform ldo3: voltage selector settings: reg: 0x51, mask: 0xf
[    2.094593] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.105530] ldo3: hi6421_spmi_regulator_enable: off_on_delay=20000 us, enable_reg=0x16, enable_mask=0x1
[    2.153484] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.163409] ldo3: 1500 <--> 2000 mV at 1800 mV normal 
[    2.181305] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
[    2.191289] ldo3: hi6421_spmi_regulator_probe_ldo: valid_modes_mask: 0x2, valid_ops_mask: 0x9

As the name which got printed is the one that actually makes sense
for someone working with the driver, as it matches the DT entries
and the hardware power supply lines.

> > +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;
> > +
> > +	/* unlikely to happen. sanity test done by regulator core */  
> 
> Unlikely or can't?
> 
> > +	if (unlikely(selector >= rdev->desc->n_voltages))
> > +		return -EINVAL;

Good question. I almost removed this check, but I didn't check the
regulator code with enough care to be 100% sure. So, I opted to keep it
here.

> > +
> > +	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;
> > +	u32 reg_val;
> > +	unsigned int mode;
> > +
> > +	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)) {
> > +		rdev_dbg(rdev, "normal mode");  
> 
> Debug seems unnecessary to me, but maybe keep it if you want.

I actually used this debug. There are some LDO lines which don't
support eco mode. The original driver was hard to understand that.
So, I ended by re-writing the part of the code which sets/uses it[1]:

+	/* 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;
+	}
+

[1] https://lore.kernel.org/lkml/176043f329dfa9889f014feec04e7e1553077873.1597160086.git.mchehab+huawei@kernel.org/T/#m337e09adf04e4b8ce56af93ba37e3720b2a3002b

Those debug messages are useful to double-check if something bad is
not happening with the modes/ops masks.


> > +	/* register regulator */
> > +	rdev = regulator_register(rdesc, &config);
> > +	if (IS_ERR(rdev)) {
> > +		dev_err(dev, "failed to register %s\n",
> > +			rdesc->name);
> > +		ret = PTR_ERR(rdev);
> > +		goto probe_end;
> > +	}
> > +
> > +	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);  
> I'd do separate error path.
> 
> 	return 0;
> 
> > +probe_end:
> > +	if (ret)  
> 
> ret is set if separate error path.
> I haven't figured out lifetime but can we not use devm for sreg?
> 
> > +		kfree(sreg);

I guess we can. I'll check and change if ok.

> > +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);
> > +
> > +	/* TODO: should i worry about that? devm_kzalloc */  
> 
> Answer that TODO.  No unless something odd going on.

Yeah, agreed. I'll cleanup useless comments on this driver.

> 
> > +	if (rdev->desc->volt_table)
> > +		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
> > +
> > +	kfree(sreg);  
> 
> This is a worrying mix of devm and not.  Never a good sign.
> Lifetime of sreg seems strange.

I guess we can just get rid of both, converting sreg to use devm alloc.

Btw, at least on Hikey 970 (which happens to be the only board using
it so far), in practice this driver should never be removed, as, among 
other things, it controls the power supply for storage (both SD and
MMC).


> > diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
> > index a53bad541f1a..b44e2ab6bf81 100644
> > --- a/drivers/spmi/Kconfig
> > +++ b/drivers/spmi/Kconfig
> > @@ -25,4 +25,13 @@ config SPMI_MSM_PMIC_ARB
> >  	  This is required for communicating with Qualcomm PMICs and
> >  	  other devices that have the SPMI interface.
> >  
> > +config SPMI_HISI3670
> > +	tristate "Hisilicon 3670 SPMI Controller"
> > +	select IRQ_DOMAIN_HIERARCHY
> > +	depends on HAS_IOMEM  
> 
> I have a vague recollection some magic was done to mean we don't need that
> any more (stubs for the few cases where it doesn't exist).
> Could have remembered wrong though.

Yeah, I also have a vage remind about HAS_IOMEM and stubs at the headers
(or some other config option similar to it), but not really sure.

There is just another SPMI driver. So, I ended playing safe here by
duplicating select/depends on from the previous entry. Btw,
there are several other places with the same pattern.

> > +	/* 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, sid, addr);
> > +	spin_unlock_irqrestore(&spmi_controller->lock, flags);
> > +
> > +	if (rc)
> > +		dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x sid:%d addr:0x%x bc:%ld\n",
> > +			opc, sid, addr, bc);
> > +	else
> > +		dev_dbg(&ctrl->dev, "%s: id:%d addr:0x%x, wrote value: %*ph\n",
> > +			__func__, sid, addr, (int)bc, __buf);  
> 
> I'd drop the debug.  Adds a lot of code for limited benefit.

Yeah, I guess this can now be dropped. That was required while
fixing some endianness issues at the past code.

> > +	ret = spmi_controller_add(ctrl);
> > +	if (ret)
> > +		goto err_add_controller;
> > +
> > +	dev_info(&pdev->dev, "spmi_add_controller initialized\n");  
> 
> Too noisy.

That's helpful to check if drivers initialized at the right order.

I'll change it to dev_dbg().

> 
> > +	return 0;
> > +
> > +err_add_controller:
> > +	dev_err(&pdev->dev, "spmi_add_controller failed!\n");  
> 
> Seems too noisy to me given information provided is minimal.

I'll add the error code to the message.

> > diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
> > index c16b60f645a4..253340e10dab 100644
> > --- a/drivers/spmi/spmi.c
> > +++ b/drivers/spmi/spmi.c  
> 
> All the changes in here look to be cleanup.  Drop it from this series
> as it just adds noise.

Yeah, makes sense. Will submit it on a separate patch.

> > @@ -545,13 +548,10 @@ static int spmi_ctrl_remove_device(struct device *dev, void *data)
> >   */
> >  void spmi_controller_remove(struct spmi_controller *ctrl)
> >  {
> > -	int dummy;
> > -
> >  	if (!ctrl)
> >  		return;
> >  
> > -	dummy = device_for_each_child(&ctrl->dev, NULL,
> > -				      spmi_ctrl_remove_device);
> > +	device_for_each_child(&ctrl->dev, NULL, spmi_ctrl_remove_device);
> >  	device_del(&ctrl->dev);
> >  }
> >  EXPORT_SYMBOL_GPL(spmi_controller_remove);  

This one is on a separate patch already. Will submit in separate.

Thanks,
Mauro

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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-12  7:45     ` Mauro Carvalho Chehab
@ 2020-08-12  8:43       ` Jonathan Cameron
  2020-08-12 10:38         ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 48+ messages in thread
From: Jonathan Cameron @ 2020-08-12  8:43 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, linux-kernel, devicetree, Stephen Boyd,
	linux-arm-msm, Mark Brown, Mayulong, linuxarm, Liam Girdwood,
	Rob Herring, Lee Jones, David S. Miller, linux-arm-kernel

On Wed, 12 Aug 2020 09:45:40 +0200
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:

....

> 
> >   
> > >  	  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
> > > +	select MFD_CORE
> > > +	select REGMAP_MMIO    
> > 
> > Nice thought, but it doesn't use it yet!  
> 
> What do you mean? Makefile should be using it:
> 
> 	$ git grep MFD_HI6421_SPMI
> 	drivers/mfd/Kconfig:config MFD_HI6421_SPMI
> 	drivers/mfd/Makefile:obj-$(CONFIG_MFD_HI6421_SPMI)      += hi6421-spmi-pmic.o

Just the REGMAP bit.  Driver doesn't seem to be using regmap.

> 
> 
> > > + *
> > > + */
> > > +
> > > +#include <linux/slab.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/device.h>
> > > +#include <linux/module.h>
> > > +#include <linux/err.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/mfd/core.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/of_gpio.h>
> > > +#include <linux/of_irq.h>
> > > +#include <linux/mfd/hi6421-spmi-pmic.h>
> > > +#include <linux/irq.h>
> > > +#include <linux/spmi.h>
> > > +#ifndef NO_IRQ
> > > +#define NO_IRQ       0    
> > 
> > Drop  
> 
> Ok! I was in doubt about that, as there are a few other drivers with
> the same pattern:
> 
> 	drivers/ata/sata_dwc_460ex.c:#define NO_IRQ             0
> 	drivers/input/touchscreen/ucb1400_ts.c:#define NO_IRQ   0
> 	drivers/mmc/host/of_mmc_spi.c:#define NO_IRQ 0
> 	drivers/pcmcia/pd6729.c:#define NO_IRQ  ((unsigned int)(0))
> 	drivers/rtc/rtc-m48t59.c:#define NO_IRQ (-1)
> 
> Btw, this definition at the rtc driver sounds weird ;-)

History I guess.   IIRC, a long time back, 0 was a valid IRQ for some architectures.


> 
> > > +	/*SOC_PMIC_IRQ0_ADDR*/    
> > 
> > These superficially feel like things that would come from
> > the compatible, but maybe I'm missing something.  
> 
> My guess is that this is decided by the board manufacturer. I mean,
> from the schematics:
> 
> 	https://www.96boards.org/documentation/consumer/hikey/hikey970/hardware-docs/files/hikey970-schematics.pdf
> 
> This is a separate chipset, connected at the Kirin 970 SPMI bus. The SPMI bus
> allows up to 16 PMICs. So, I would assume that a chip designed to support
> SPMI would have the flexibility of using different IRQ lines, being
> programmable either via some firmware or via some wiring.
> 
> Without knowing more, IMO the best would be to keep those settings
> at DT.

Fair enough. Would be nice if they could be established from a bus ID of
some type and the compatible but if we don't have the info to be able to
do that I guess we will have to do it this way.



> >   
> > > +	ret = get_pmic_device_tree_data(np, pmic);
> > > +	if (ret) {
> > > +		dev_err(&pdev->dev, "Error reading hisi pmic dts\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* TODO: get and enable clk request */
> > > +	spin_lock_init(&pmic->lock);
> > > +
> > > +	pmic->dev = dev;
> > > +
> > > +	pmic->gpio = of_get_gpio_flags(np, 0, &flags);    
> > 
> > Do we need flags for something?
> > 
> > Can we use the gpio/consumer.h interfaces for all this?
> > 
> > Though I'm not sure we need a gpio at all. Looks like we just
> > use it as an interrupt.  Get an interrupt directly instead.  
> 
> Yeah, from what I saw, the GPIOs supported right now by this driver
> are just for IRQs.

Guess they all need switching to just being interrupt lines then.

> 
> > > +	if (pmic->gpio < 0)
> > > +		return pmic->gpio;
> > > +
> > > +	if (!gpio_is_valid(pmic->gpio))
> > > +		return -EINVAL;
> > > +
> > > +	ret = gpio_request_one(pmic->gpio, GPIOF_IN, "pmic");
> > > +	if (ret < 0) {
> > > +		dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
> > > +		return ret;
> > > +	}
> > > +
> > > +	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 %d\n", ret);
> > > +		ret = -ENODEV;
> > > +		goto request_theaded_irq;
> > > +	}
> > > +
> > > +	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);    
> > 
> > This is mixing and matching managed an unmanaged. Should be one or the other
> > or we might be hiding some race conditions.  

I intended this as a more localized comment, though the following answers
another question I had.

request_threaded_irq is not using devm_ whilst the add devices is.
As a result we might have a path in which the irq goes away before
the device cleanup happens.   

> 
> Actually, it is just the opposite. It took me a lot of time to
> figure out a good solution that will prevent all race conditions at
> probe time.
> 
> See, the SPMI variant of HiSilicon 6421 requires the drivers to be
> probed on a very specific order:
> 
> - The SPMI controller should be loaded first, as it provides 
>   the low-level I/O access to the serial bus used to talk with the
>   PMICs. This bus is somewhat similar to the I2C bus.
> 
>   Once the controller is registered, the SPMI bus probes the PMIC
>   driver.
> 
> - Then, the MFD PMIC driver should be loaded. This adds support for
>   a high level set of I/O operations, which are used by the regulator
>   driver. Again, this approach is similar to the one taken by the
>   I2C Kernel drivers.
> 
> - Finally, the regulator drivers should come, as they rely on the
>   MFD I/O operations in order to talk with the SPMI bus.
> 
> The OOT driver probing was based on a some dirty hacks: it had an
> empty SPMI entry at the SoC, carrying on just the "compatible" line.
> 
> Then, another entry at DT with the real SPMI settings.
> 
> With such dirty hack, on Kernel 4.9, the PMIC driver were always 
> loading before the regulator ones, as the SPMI bus code were 
> serializing the probe there.
> 
> However, such settings were too fragile and broke after porting to
> upstream Kernels, because the regulator drivers were probed on
> a random order, typically before the MFD one (and sometimes even 
> before the SPMI controller driver). Adding EPROBE_DEFER didn't
> solve all the issues, and made a complex and hard to debug scenario.
> Also, regulators were probed on a random order, making harder to
> debug issues there.

There are no ordering guarantees IIRC in mfd children coming up even
in the normal path.  It might currently happen in a particular order
but relying on that seems fragile to me.

> 
> So, I ended using the same solution used by the already-existing
> drivers/mfd/hi6421-pmic-core.c driver[1].
> 
> [1] This variant of the 6421 chipset is a lot simpler, as it
>     doesn't use the SPMI bus.
> 
> With such approach, the probing is warranted to happen the
> way it is expected by the driver:
> 
> SPMI controller code starts:
> 	[    0.416862] spmi_controller fff24000.spmi: HISI SPMI probe
> 	[    0.422419] spmi spmi-0: allocated controller 0x(____ptrval____) id 0
> 	[    0.428929] spmi_controller fff24000.spmi: spmi_add_controller base addr=0xffff800012055000!
> 	[    0.437480] spmi spmi-0: adding child /spmi@fff24000/pmic@0
> 	[    0.443109] spmi spmi-0: read usid 00
> 	[    0.446821] spmi 2-00: device 2-00 registered
> 	[    0.451220] spmi spmi-0: spmi-2 registered: dev:(____ptrval____)
> 	[    0.457286] spmi_controller fff24000.spmi: spmi_add_controller initialized
> 
> The PMIC probe happens sometime after spmi_controller registers itself
> at the SPMI bus:
> 
> 	[    1.955838] [hi6421_spmi_pmic_probe]. pmic->irqs[0] = 43
> ...
> 	[    2.036298] [hi6421_spmi_pmic_probe]. pmic->irqs[15] = 58
> 
> After being ready to handle I/O requests, it starts probing the
> regulators:
> 
> 	[    2.057815] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo3@16
> 	[    2.199827] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo4@17
> 	[    2.336284] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo9@1C
> 	[    2.472675] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo15@21
> 	[    2.609402] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo16@22
> 	[    2.746378] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo17@23
> 	[    2.846707] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo33@32
> 	[    2.988646] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo34@33
> 
> As the current code serializes the regulator probing, it ensured that
> they'll happen at the right order, avoiding race conditions at
> probe time.

Why do we need the regulators to come up in a particular order?
That sounds suspicious as any relationships between different ones should be expressed
either in DT or in the order they are enabled in the drivers using them.

> 
> > 
> >   

> > > diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> > > index edb1c4f8b496..de8a78487bb9 100644
> > > --- a/drivers/regulator/Kconfig
> > > +++ b/drivers/regulator/Kconfig
> > > @@ -356,6 +356,14 @@ config REGULATOR_HI6421V530
> > >  	  provides 5 general purpose LDOs, and all of them come with support
> > >  	  to either ECO (idle) or sleep mode.
> > >  
> > > +config REGULATOR_HI6421V600
> > > +	tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
> > > +	depends on MFD_HI6421_PMIC && OF    
> > 
> > Can we do a COMPILE_TEST here?  
> 
> Neither REGULATOR_HI6421V600 nor MFD_HI6421_PMIC depends on ARM or
> ARM64, so they should build fine on any arch. So, I'm failing to see
> why adding COMPILE_TEST would make any difference.

cool. Good to get the extra build coverage.

> 
> > > +
> > > +#include <linux/slab.h>
> > > +#include <linux/device.h>
> > > +#include <linux/module.h>
> > > +#include <linux/err.h>
> > > +#include <linux/io.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/regulator/driver.h>
> > > +#include <linux/regulator/machine.h>
> > > +#include <linux/regulator/of_regulator.h>
> > > +#include <linux/mfd/hi6421-spmi-pmic.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/time.h>
> > > +#include <linux/version.h>
> > > +#include <linux/seq_file.h>
> > > +#include <linux/uaccess.h>
> > > +#include <linux/spmi.h>
> > > +
> > > +#define rdev_dbg(rdev, fmt, arg...)	\
> > > +		 pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg)    
> > 
> > Not worth defining in my view.  
> 
> That was my first approach: to drop any existing printk macro, replacing
> them by dev_dbg(). However, with dev_dbg(), the logs were like:
> 
> [    2.069301] platform ldo3: LDO doesn't support economy mode.
> [    2.074969] platform ldo3: voltage selector settings: reg: 0x51, mask: 0xf
> [    2.094593] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.105530] regulator.3: hi6421_spmi_regulator_enable: off_on_delay=20000 us, enable_reg=0x16, enable_mask=0x1
> [    2.153484] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.163409] ldo3: 1500 <--> 2000 mV at 1800 mV normal 
> [    2.181305] regulator.3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.191289] regulator.3: hi6421_spmi_regulator_probe_ldo: valid_modes_mask: 0x2, valid_ops_mask: 0x9
> 
> E. g. the messages printed by the regulator's core were using 
> (rdev)->desc->name on their printks, producing a nice debug
> (when enabled at core level), while dev_dbg() were using a different name.
> 
> In this specific case, one might assume that "regulator.3" is "ldo3",
> but this is by coincidence, as it actually matches the sysfs entries:
> 
> 	$ ls -l /sys/class/regulator/
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.0 -> ../../devices/platform/reg-dummy/regulator/regulator.0
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.1 -> ../../devices/platform/regulator-1v8/regulator/regulator.1
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.10 -> ../../devices/platform/spmi-0/2-00/ldo34/regulator/regulator.10
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.2 -> ../../devices/platform/wlan-en-1-8v/regulator/regulator.2
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.3 -> ../../devices/platform/spmi-0/2-00/ldo3/regulator/regulator.3
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.4 -> ../../devices/platform/spmi-0/2-00/ldo4/regulator/regulator.4
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.5 -> ../../devices/platform/spmi-0/2-00/ldo9/regulator/regulator.5
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.6 -> ../../devices/platform/spmi-0/2-00/ldo15/regulator/regulator.6
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.7 -> ../../devices/platform/spmi-0/2-00/ldo16/regulator/regulator.7
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.8 -> ../../devices/platform/spmi-0/2-00/ldo17/regulator/regulator.8
> 	lrwxrwxrwx 1 root root 0 ago 12 08:26 regulator.9 -> ../../devices/platform/spmi-0/2-00/ldo33/regulator/regulator.9
> 
> When playing with DT, the "regulator.[\d+]" namespace may change,
> making harder to debug stuff. So, basically, enabling just the logs
> at the regulator driver were requiring to double-check the sysfs 
> entries in order to see what "regulator.3" were actually meaning
> with a particular DT setting.
> 
> After adding the macro, the output is a lot easier to be understood:
> 
> [    2.069301] platform ldo3: LDO doesn't support economy mode.
> [    2.074969] platform ldo3: voltage selector settings: reg: 0x51, mask: 0xf
> [    2.094593] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.105530] ldo3: hi6421_spmi_regulator_enable: off_on_delay=20000 us, enable_reg=0x16, enable_mask=0x1
> [    2.153484] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.163409] ldo3: 1500 <--> 2000 mV at 1800 mV normal 
> [    2.181305] ldo3: hi6421_spmi_regulator_get_voltage_sel: vsel_reg=0x51, value=0x8, entry=0x8, voltage=1800 mV
> [    2.191289] ldo3: hi6421_spmi_regulator_probe_ldo: valid_modes_mask: 0x2, valid_ops_mask: 0x9
> 
> As the name which got printed is the one that actually makes sense
> for someone working with the driver, as it matches the DT entries
> and the hardware power supply lines.

Fair enough.  Guess this is one for Mark to ultimately decide.

> 
> > > +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;
> > > +
> > > +	/* unlikely to happen. sanity test done by regulator core */    
> > 
> > Unlikely or can't?
> >   
> > > +	if (unlikely(selector >= rdev->desc->n_voltages))
> > > +		return -EINVAL;  
> 
> Good question. I almost removed this check, but I didn't check the
> regulator code with enough care to be 100% sure. So, I opted to keep it
> here.

I'd drop the comment then :)  If someone else wants to figure it out
in future then they are welcome to.

> 
> > > +
> > > +	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;
> > > +	u32 reg_val;
> > > +	unsigned int mode;
> > > +
> > > +	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)) {
> > > +		rdev_dbg(rdev, "normal mode");    
> > 
> > Debug seems unnecessary to me, but maybe keep it if you want.  
> 
> I actually used this debug. There are some LDO lines which don't
> support eco mode. The original driver was hard to understand that.
> So, I ended by re-writing the part of the code which sets/uses it[1]:
> 
> +	/* 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;
> +	}
> +
> 
> [1] https://lore.kernel.org/lkml/176043f329dfa9889f014feec04e7e1553077873.1597160086.git.mchehab+huawei@kernel.org/T/#m337e09adf04e4b8ce56af93ba37e3720b2a3002b
> 
> Those debug messages are useful to double-check if something bad is
> not happening with the modes/ops masks.

That's fine, but is it useful to have it upstream now you have debugged
those issues?  I'm not completely convinced it is and debug prints have
a habit of rotting just like comments.

> 
> 
> > > +	/* register regulator */
> > > +	rdev = regulator_register(rdesc, &config);
> > > +	if (IS_ERR(rdev)) {
> > > +		dev_err(dev, "failed to register %s\n",
> > > +			rdesc->name);
> > > +		ret = PTR_ERR(rdev);
> > > +		goto probe_end;
> > > +	}
> > > +
> > > +	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);    
> > I'd do separate error path.
> > 
> > 	return 0;
> >   
> > > +probe_end:
> > > +	if (ret)    
> > 
> > ret is set if separate error path.
> > I haven't figured out lifetime but can we not use devm for sreg?
> >   
> > > +		kfree(sreg);  
> 
> I guess we can. I'll check and change if ok.
> 
> > > +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);
> > > +
> > > +	/* TODO: should i worry about that? devm_kzalloc */    
> > 
> > Answer that TODO.  No unless something odd going on.  
> 
> Yeah, agreed. I'll cleanup useless comments on this driver.
> 
> >   
> > > +	if (rdev->desc->volt_table)
> > > +		devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table);
> > > +
> > > +	kfree(sreg);    
> > 
> > This is a worrying mix of devm and not.  Never a good sign.
> > Lifetime of sreg seems strange.  
> 
> I guess we can just get rid of both, converting sreg to use devm alloc.
> 
> Btw, at least on Hikey 970 (which happens to be the only board using
> it so far), in practice this driver should never be removed, as, among 
> other things, it controls the power supply for storage (both SD and
> MMC).

Who needs storage? :)


...
> 
> > > +	ret = spmi_controller_add(ctrl);
> > > +	if (ret)
> > > +		goto err_add_controller;
> > > +
> > > +	dev_info(&pdev->dev, "spmi_add_controller initialized\n");    
> > 
> > Too noisy.  
> 
> That's helpful to check if drivers initialized at the right order.
> 
> I'll change it to dev_dbg().

More reasonable.


thanks,

Jonathan


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

* Re: [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970
  2020-08-12  8:43       ` Jonathan Cameron
@ 2020-08-12 10:38         ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-12 10:38 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Rob Herring, linux-kernel, devicetree, Stephen Boyd,
	linux-arm-msm, Mark Brown, Mayulong, linuxarm, Liam Girdwood,
	Rob Herring, Lee Jones, David S. Miller, linux-arm-kernel

Em Wed, 12 Aug 2020 09:43:53 +0100
Jonathan Cameron <Jonathan.Cameron@huawei.com> escreveu:

> On Wed, 12 Aug 2020 09:45:40 +0200
> Mauro Carvalho Chehab <mchehab+huawei@kernel.org> wrote:
> > > 
> > > This is mixing and matching managed an unmanaged. Should be one or the other
> > > or we might be hiding some race conditions.    
> 
> I intended this as a more localized comment, though the following answers
> another question I had.
> 
> request_threaded_irq is not using devm_ whilst the add devices is.
> As a result we might have a path in which the irq goes away before
> the device cleanup happens.   

Ah, good point! I'll address it.

> > Actually, it is just the opposite. It took me a lot of time to
> > figure out a good solution that will prevent all race conditions at
> > probe time.
> > 
> > See, the SPMI variant of HiSilicon 6421 requires the drivers to be
> > probed on a very specific order:
> > 
> > - The SPMI controller should be loaded first, as it provides 
> >   the low-level I/O access to the serial bus used to talk with the
> >   PMICs. This bus is somewhat similar to the I2C bus.
> > 
> >   Once the controller is registered, the SPMI bus probes the PMIC
> >   driver.
> > 
> > - Then, the MFD PMIC driver should be loaded. This adds support for
> >   a high level set of I/O operations, which are used by the regulator
> >   driver. Again, this approach is similar to the one taken by the
> >   I2C Kernel drivers.
> > 
> > - Finally, the regulator drivers should come, as they rely on the
> >   MFD I/O operations in order to talk with the SPMI bus.
> > 
> > The OOT driver probing was based on a some dirty hacks: it had an
> > empty SPMI entry at the SoC, carrying on just the "compatible" line.
> > 
> > Then, another entry at DT with the real SPMI settings.
> > 
> > With such dirty hack, on Kernel 4.9, the PMIC driver were always 
> > loading before the regulator ones, as the SPMI bus code were 
> > serializing the probe there.
> > 
> > However, such settings were too fragile and broke after porting to
> > upstream Kernels, because the regulator drivers were probed on
> > a random order, typically before the MFD one (and sometimes even 
> > before the SPMI controller driver). Adding EPROBE_DEFER didn't
> > solve all the issues, and made a complex and hard to debug scenario.
> > Also, regulators were probed on a random order, making harder to
> > debug issues there.  
> 
> There are no ordering guarantees IIRC in mfd children coming up even
> in the normal path.  It might currently happen in a particular order
> but relying on that seems fragile to me.

True, but in the case of SPMI controller and PMIC, there's no way
to support them to be initialized on a random order.

That's why the approach I took is serializing the probe.

> > 
> > So, I ended using the same solution used by the already-existing
> > drivers/mfd/hi6421-pmic-core.c driver[1].
> > 
> > [1] This variant of the 6421 chipset is a lot simpler, as it
> >     doesn't use the SPMI bus.
> > 
> > With such approach, the probing is warranted to happen the
> > way it is expected by the driver:
> > 
> > SPMI controller code starts:
> > 	[    0.416862] spmi_controller fff24000.spmi: HISI SPMI probe
> > 	[    0.422419] spmi spmi-0: allocated controller 0x(____ptrval____) id 0
> > 	[    0.428929] spmi_controller fff24000.spmi: spmi_add_controller base addr=0xffff800012055000!
> > 	[    0.437480] spmi spmi-0: adding child /spmi@fff24000/pmic@0
> > 	[    0.443109] spmi spmi-0: read usid 00
> > 	[    0.446821] spmi 2-00: device 2-00 registered
> > 	[    0.451220] spmi spmi-0: spmi-2 registered: dev:(____ptrval____)
> > 	[    0.457286] spmi_controller fff24000.spmi: spmi_add_controller initialized
> > 
> > The PMIC probe happens sometime after spmi_controller registers itself
> > at the SPMI bus:
> > 
> > 	[    1.955838] [hi6421_spmi_pmic_probe]. pmic->irqs[0] = 43
> > ...
> > 	[    2.036298] [hi6421_spmi_pmic_probe]. pmic->irqs[15] = 58
> > 
> > After being ready to handle I/O requests, it starts probing the
> > regulators:
> > 
> > 	[    2.057815] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo3@16
> > 	[    2.199827] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo4@17
> > 	[    2.336284] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo9@1C
> > 	[    2.472675] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo15@21
> > 	[    2.609402] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo16@22
> > 	[    2.746378] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo17@23
> > 	[    2.846707] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo33@32
> > 	[    2.988646] hi6421v600-regulator hi6421v600-regulator: adding child /spmi@fff24000/pmic@0/regulators/ldo34@33
> > 
> > As the current code serializes the regulator probing, it ensured that
> > they'll happen at the right order, avoiding race conditions at
> > probe time.  
> 
> Why do we need the regulators to come up in a particular order?
> That sounds suspicious as any relationships between different ones should be expressed
> either in DT or in the order they are enabled in the drivers using them.

There's no need for them to come up on a particular order.

What I meant to say is that the that the SPMI controller and MFD
should go first.

- 

Yet, incidentally, the current code also serializes the regulator
probe. I could have written the code on a different way that
would allow them to be probed in parallel, by moving a loop
from the regulator driver to the PMIC one. However, I don't see any 
advantage on doing that, as the regulator initialization code ends 
calling the SPMI serial bus, whose access is already serialized by 
a spinlock.

So, there's no performance gain by allowing them to be probed
in parallel, as most of the regulator's probing time is probably
waiting for the relatively slow I/O serial transfers to happen. 

Also, a nice a side effect of serializing the probe at the 
regulator driver is that the devices are ordered according
their LDO numbers, and the debug logs from probing time will
be altogether, helping to debug potential issues over there.

> > > > +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;
> > > > +
> > > > +	/* unlikely to happen. sanity test done by regulator core */      
> > > 
> > > Unlikely or can't?
> > >     
> > > > +	if (unlikely(selector >= rdev->desc->n_voltages))
> > > > +		return -EINVAL;    
> > 
> > Good question. I almost removed this check, but I didn't check the
> > regulator code with enough care to be 100% sure. So, I opted to keep it
> > here.  
> 
> I'd drop the comment then :)  If someone else wants to figure it out
> in future then they are welcome to.

Ok.

> > > > +	if (load_uA || ((unsigned int)load_uA > sreg->eco_uA)) {
> > > > +		rdev_dbg(rdev, "normal mode");      
> > > 
> > > Debug seems unnecessary to me, but maybe keep it if you want.    
> > 
> > I actually used this debug. There are some LDO lines which don't
> > support eco mode. The original driver was hard to understand that.
> > So, I ended by re-writing the part of the code which sets/uses it[1]:
> > 
> > +	/* 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;
> > +	}
> > +
> > 
> > [1] https://lore.kernel.org/lkml/176043f329dfa9889f014feec04e7e1553077873.1597160086.git.mchehab+huawei@kernel.org/T/#m337e09adf04e4b8ce56af93ba37e3720b2a3002b
> > 
> > Those debug messages are useful to double-check if something bad is
> > not happening with the modes/ops masks.  
> 
> That's fine, but is it useful to have it upstream now you have debugged
> those issues?  I'm not completely convinced it is and debug prints have
> a habit of rotting just like comments.

Good point. I'll do a review at the printks inside the driver anyway.

I'll try to cleanup some things that doesn't make much sense
after having the driver working properly.


Thanks,
Mauro

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

* Re: [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties
  2020-08-11 15:41 ` [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties Mauro Carvalho Chehab
@ 2020-08-12 16:30   ` Rob Herring
  2020-08-12 18:55     ` Mauro Carvalho Chehab
  0 siblings, 1 reply; 48+ messages in thread
From: Rob Herring @ 2020-08-12 16:30 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: Rob Herring, linuxarm, devicetree, Stephen Boyd, linux-arm-msm,
	linux-kernel, Lee Jones, mauro.chehab

On Tue, 11 Aug 2020 17:41:57 +0200, Mauro Carvalho Chehab wrote:
> Add documentation for the properties needed by the HiSilicon
> 6421v600 driver, and by the SPMI controller used to access
> the chipset.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
>  .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 175 ++++++++++++++++++
>  .../spmi/hisilicon,hisi-spmi-controller.yaml  |  54 ++++++
>  2 files changed, 229 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
>  create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> 


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

Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: $id: relative path/filename doesn't match actual path or filename
	expected: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:34.15-28: Warning (reg_format): /example-0/pmic@0/regulators/ldo3@16:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:57.15-28: Warning (reg_format): /example-0/pmic@0/regulators/ldo4@17:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (pci_device_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:33.27-54.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo3@16: Relying on default #address-cells value
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:33.27-54.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo3@16: Relying on default #size-cells value
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:56.27-76.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo4@17: Relying on default #address-cells value
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:56.27-76.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo4@17: Relying on default #size-cells value
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (unique_unit_address): Failed prerequisite 'avoid_default_addr_size'
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: example-0: spmi@fff24000:reg:0: [0, 4294066176, 0, 4096] is too long
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: spmi@fff24000: spmi-channel:0: 'number of the SPMI channel where the PMIC is connected' was expected
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: pmic@0: 'spmi-channel' is a required property


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

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

pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade

Please check and re-submit.


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

* Re: [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties
  2020-08-12 16:30   ` Rob Herring
@ 2020-08-12 18:55     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 48+ messages in thread
From: Mauro Carvalho Chehab @ 2020-08-12 18:55 UTC (permalink / raw)
  To: Rob Herring
  Cc: Rob Herring, linuxarm, devicetree, Stephen Boyd, linux-arm-msm,
	linux-kernel, Lee Jones, mauro.chehab

Em Wed, 12 Aug 2020 10:30:36 -0600
Rob Herring <robh@kernel.org> escreveu:

> On Tue, 11 Aug 2020 17:41:57 +0200, Mauro Carvalho Chehab wrote:
> > Add documentation for the properties needed by the HiSilicon
> > 6421v600 driver, and by the SPMI controller used to access
> > the chipset.
> > 
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > ---
> >  .../mfd/hisilicon,hi6421-spmi-pmic.yaml       | 175 ++++++++++++++++++
> >  .../spmi/hisilicon,hisi-spmi-controller.yaml  |  54 ++++++
> >  2 files changed, 229 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> >  create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> >   
> 
> 
> My bot found errors running 'make dt_binding_check' on your patch:
> 
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: $id: relative path/filename doesn't match actual path or filename
> 	expected: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:34.15-28: Warning (reg_format): /example-0/pmic@0/regulators/ldo3@16:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:57.15-28: Warning (reg_format): /example-0/pmic@0/regulators/ldo4@17:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (pci_device_reg): Failed prerequisite 'reg_format'
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (simple_bus_reg): Failed prerequisite 'reg_format'
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:33.27-54.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo3@16: Relying on default #address-cells value
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:33.27-54.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo3@16: Relying on default #size-cells value
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:56.27-76.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo4@17: Relying on default #address-cells value
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dts:56.27-76.15: Warning (avoid_default_addr_size): /example-0/pmic@0/regulators/ldo4@17: Relying on default #size-cells value
> Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: Warning (unique_unit_address): Failed prerequisite 'avoid_default_addr_size'
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: example-0: spmi@fff24000:reg:0: [0, 4294066176, 0, 4096] is too long
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: spmi@fff24000: spmi-channel:0: 'number of the SPMI channel where the PMIC is connected' was expected
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml: pmic@0: 'spmi-channel' is a required property
> 
> 
> See https://patchwork.ozlabs.org/patch/1343370
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure dt-schema is up to date:
> 
> pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
> 
> Please check and re-submit.
> 

Hi Rob,

Fixed those at the newest version I submitted today via staging tree.

At least here, dt_binding_check passes at the newest version.

Regards,
Mauro





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

end of thread, other threads:[~2020-08-12 18:55 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-11 15:41 [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 01/33] spmi: get rid of a warning when built with W=1 Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 02/33] spmi, regulator, mfd: add drivers for hikey970 SPMI PMIC Mauro Carvalho Chehab
2020-08-11 15:58   ` Mark Brown
2020-08-11 16:08     ` Mauro Carvalho Chehab
2020-08-11 16:15       ` Mark Brown
2020-08-11 16:35         ` Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 03/33] spmi: hisi-spmi-controller: coding style fixup Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 04/33] mfd, regulator: get rid of unused code at HiSilicon SPMI PMIC Mauro Carvalho Chehab
2020-08-11 16:00   ` Mark Brown
2020-08-11 15:41 ` [PATCH 05/33] regulator: hisi_regulator_spmi: port it to upstream Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 06/33] mfd: hisi_pmic_spmi: deal with non-static functions Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 07/33] mfd: hisi_pmic_spmi: get rid of the static vars Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 08/33] spmi: hisi-spmi-controller: fix it to probe successfully Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 09/33] spmi: hisi-spmi-controller: fix a typo Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 10/33] spmi: hisi-spmi-controller: adjust whitespaces at defines Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 11/33] spmi: hisi-spmi-controller: use le32 macros where needed Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 12/33] spmi: hisi-spmi-controller: add debug when values are read/write Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 13/33] mfd, regulator: coding style fixups at the HiSilicon SPMI PMIC code Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 14/33] spmi: add hisi-spmi-controller to the building system Mauro Carvalho Chehab
2020-08-11 20:53   ` kernel test robot
2020-08-11 15:41 ` [PATCH 15/33] mfd: Kconfig: fix a typo Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 16/33] spmi: hisi-spmi-controller: fix the dev_foo() logic Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 17/33] mfd: pmic: add drivers for hi6421v600 Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 18/33] mfd: hi6421-spmi-pmic: get rid of unused OF properties Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 19/33] spmi: hi6421-spmi-pmic: cleanup " Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 20/33] regulator: hi6421v600-regulator: cleanup struct hisi_regulator Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 21/33] regulator: hi6421v600-regulator: cleanup debug messages Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 22/33] regulator: hi6421v600-regulator: use shorter names for OF properties Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 23/33] regulator: hi6421v600-regulator: better handle modes Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 24/33] regulator, mfd: change namespace for HiSilicon SPMI PMIC drivers Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 25/33] regulator: hi6421v600-regulator: convert to use get/set voltage_sel Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 26/33] regulator: hi6421v600-regulator: don't use usleep_range for off_on_delay Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 27/33] regulator: hi6421v600-regulator: add a driver-specific debug macro Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 28/33] regulator: hi6421v600-regulator: initialize ramp_delay Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 29/33] regulator: hi6421v600-regulator: cleanup DT settings Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 30/33] mfd, spmi, regulator: fix some coding style issues at HiSilicon SPMI PMIC Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 31/33] dt: document HiSilicon SPMI controller and mfd/regulator properties Mauro Carvalho Chehab
2020-08-12 16:30   ` Rob Herring
2020-08-12 18:55     ` Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 32/33] dt: hisilicon: add support for the PMIC found on Hikey 970 Mauro Carvalho Chehab
2020-08-11 15:41 ` [PATCH 33/33] MAINTAINERS: add an entry for HiSilicon 6421v600 drivers Mauro Carvalho Chehab
2020-08-11 15:54 ` [PATCH 00/33] Add driver for HiSilicon SPMI PMIC for Hikey 970 Mauro Carvalho Chehab
2020-08-11 17:51   ` Jonathan Cameron
2020-08-12  7:45     ` Mauro Carvalho Chehab
2020-08-12  8:43       ` Jonathan Cameron
2020-08-12 10:38         ` Mauro Carvalho Chehab
2020-08-11 16:09 ` Mark Brown

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).