* [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging
2021-01-19 16:10 [PATCH v4 00/21] Move Hisilicon 6421v600 SPMI driver set out of staging Mauro Carvalho Chehab
@ 2021-01-19 16:10 ` Mauro Carvalho Chehab
2021-02-05 22:19 ` Rob Herring
2021-01-19 16:10 ` [PATCH v4 18/21] mfd: hi6421-spmi-pmic: " Mauro Carvalho Chehab
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2021-01-19 16:10 UTC (permalink / raw)
To: Mark Brown, Lee Jones
Cc: Mauro Carvalho Chehab, Colin Ian King, Dan Carpenter,
Greg Kroah-Hartman, Mayulong, Rob Herring, Stephen Boyd,
YueHaibing, devel, devicetree, linux-arm-msm, linux-kernel
The Hisilicon 6421v600 SPMI driver is ready for mainstream.
So, move it from staging.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.../spmi/hisilicon,hisi-spmi-controller.yaml | 75 ++++
MAINTAINERS | 7 +
drivers/spmi/Kconfig | 9 +
drivers/spmi/Makefile | 1 +
drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++++++++++
drivers/staging/hikey9xx/Kconfig | 11 -
drivers/staging/hikey9xx/Makefile | 1 -
.../staging/hikey9xx/hisi-spmi-controller.c | 358 ------------------
.../hisilicon,hisi-spmi-controller.yaml | 75 ----
9 files changed, 450 insertions(+), 445 deletions(-)
create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
create mode 100644 drivers/spmi/hisi-spmi-controller.c
delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
new file mode 100644
index 000000000000..21f68a9c2df1
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon SPMI controller
+
+maintainers:
+ - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+description: |
+ The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
+ It is a MIPI System Power Management (SPMI) controller.
+
+ The PMIC part is provided by
+ drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
+
+properties:
+ $nodename:
+ pattern: "spmi@[0-9a-f]"
+
+ compatible:
+ const: hisilicon,kirin970-spmi-controller
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 0
+
+ spmi-channel:
+ description: |
+ number of the Kirin 970 SPMI channel where the SPMI devices are connected.
+
+required:
+ - compatible
+ - reg
+ - spmi-channel
+ - "#address-cells"
+ - "#size-cells"
+
+patternProperties:
+ "^pmic@[0-9a-f]$":
+ description: |
+ PMIC properties, which are specific to the used SPMI PMIC device(s).
+ When used in combination with HiSilicon 6421v600, the properties
+ are documented at
+ drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
+
+additionalProperties: false
+
+examples:
+ - |
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ spmi: spmi@fff24000 {
+ compatible = "hisilicon,kirin970-spmi-controller";
+ #address-cells = <2>;
+ #size-cells = <0>;
+ status = "ok";
+ reg = <0x0 0xfff24000 0x0 0x1000>;
+ spmi-channel = <2>;
+
+ pmic@0 {
+ reg = <0 0>;
+ /* pmic properties */
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 8d858e8d5a52..85e5b6ab57ca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7999,6 +7999,13 @@ F: drivers/crypto/hisilicon/sec2/sec_crypto.c
F: drivers/crypto/hisilicon/sec2/sec_crypto.h
F: drivers/crypto/hisilicon/sec2/sec_main.c
+HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970
+M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
+F: drivers/spmi/hisi-spmi-controller.c
+
HISILICON STAGING DRIVERS FOR HIKEY 960/970
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
L: devel@driverdev.osuosl.org
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index a53bad541f1a..2874b6c26028 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -11,6 +11,15 @@ menuconfig SPMI
if SPMI
+config SPMI_HISI3670
+ tristate "Hisilicon 3670 SPMI Controller"
+ select IRQ_DOMAIN_HIERARCHY
+ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ built-in SPMI PMIC Arbiter interface on Hisilicon 3670
+ processors.
+
config SPMI_MSM_PMIC_ARB
tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
select IRQ_DOMAIN_HIERARCHY
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 55a94cadeffe..6e092e6f290c 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,4 +4,5 @@
#
obj-$(CONFIG_SPMI) += spmi.o
+obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
new file mode 100644
index 000000000000..4be2344ad7b5
--- /dev/null
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/*
+ * SPMI register addr
+ */
+#define SPMI_CHANNEL_OFFSET 0x0300
+#define SPMI_SLAVE_OFFSET 0x20
+
+#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100
+
+#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104
+#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108
+#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c
+#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110
+
+#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200
+
+#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204
+#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208
+#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c
+#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210
+
+#define SPMI_PER_DATAREG_BYTE 4
+/*
+ * SPMI cmd register
+ */
+#define SPMI_APB_SPMI_CMD_EN BIT(31)
+#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24
+#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20
+#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16
+#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0
+
+/* Command Opcodes */
+
+enum spmi_controller_cmd_op_code {
+ SPMI_CMD_REG_ZERO_WRITE = 0,
+ SPMI_CMD_REG_WRITE = 1,
+ SPMI_CMD_REG_READ = 2,
+ SPMI_CMD_EXT_REG_WRITE = 3,
+ SPMI_CMD_EXT_REG_READ = 4,
+ SPMI_CMD_EXT_REG_WRITE_L = 5,
+ SPMI_CMD_EXT_REG_READ_L = 6,
+ SPMI_CMD_REG_RESET = 7,
+ SPMI_CMD_REG_SLEEP = 8,
+ SPMI_CMD_REG_SHUTDOWN = 9,
+ SPMI_CMD_REG_WAKEUP = 10,
+};
+
+/*
+ * SPMI status register
+ */
+#define SPMI_APB_TRANS_DONE BIT(0)
+#define SPMI_APB_TRANS_FAIL BIT(2)
+
+/* Command register fields */
+#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16
+
+/* Maximum number of support PMIC peripherals */
+#define SPMI_CONTROLLER_TIMEOUT_US 1000
+#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16
+
+struct spmi_controller_dev {
+ struct spmi_controller *controller;
+ struct device *dev;
+ void __iomem *base;
+ spinlock_t lock;
+ u32 channel;
+};
+
+static int spmi_controller_wait_for_done(struct device *dev,
+ struct spmi_controller_dev *ctrl_dev,
+ void __iomem *base, u8 sid, u16 addr)
+{
+ u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
+ u32 status, offset;
+
+ offset = SPMI_APB_SPMI_STATUS_BASE_ADDR;
+ offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
+
+ do {
+ status = readl(base + offset);
+
+ if (status & SPMI_APB_TRANS_DONE) {
+ if (status & SPMI_APB_TRANS_FAIL) {
+ dev_err(dev, "%s: transaction failed (0x%x)\n",
+ __func__, status);
+ return -EIO;
+ }
+ dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
+ return 0;
+ }
+ udelay(1);
+ } while (timeout--);
+
+ dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
+ return -ETIMEDOUT;
+}
+
+static int spmi_read_cmd(struct spmi_controller *ctrl,
+ u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
+{
+ struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+ u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+ unsigned long flags;
+ u8 *buf = __buf;
+ u32 cmd, data;
+ int rc;
+ u8 op_code, i;
+
+ if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev,
+ "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+ SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+ return -EINVAL;
+ }
+
+ switch (opc) {
+ case SPMI_CMD_READ:
+ op_code = SPMI_CMD_REG_READ;
+ break;
+ case SPMI_CMD_EXT_READ:
+ op_code = SPMI_CMD_EXT_REG_READ;
+ break;
+ case SPMI_CMD_EXT_READL:
+ op_code = SPMI_CMD_EXT_REG_READ_L;
+ break;
+ default:
+ dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
+ return -EINVAL;
+ }
+
+ cmd = SPMI_APB_SPMI_CMD_EN |
+ (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+ ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+ ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */
+ ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
+
+ spin_lock_irqsave(&spmi_controller->lock, flags);
+
+ writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+ rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+ spmi_controller->base, slave_id, slave_addr);
+ if (rc)
+ goto done;
+
+ for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+ data = readl(spmi_controller->base + chnl_ofst +
+ SPMI_SLAVE_OFFSET * slave_id +
+ SPMI_APB_SPMI_RDATA0_BASE_ADDR +
+ i * SPMI_PER_DATAREG_BYTE);
+ data = be32_to_cpu((__force __be32)data);
+ if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+ memcpy(buf, &data, sizeof(data));
+ buf += sizeof(data);
+ } else {
+ memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
+ buf += (bc % SPMI_PER_DATAREG_BYTE);
+ }
+ }
+
+done:
+ spin_unlock_irqrestore(&spmi_controller->lock, flags);
+ if (rc)
+ dev_err(&ctrl->dev,
+ "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
+ opc, slave_id, slave_addr, bc + 1);
+ else
+ dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
+ __func__, slave_id, slave_addr, (int)bc, __buf);
+
+ return rc;
+}
+
+static int spmi_write_cmd(struct spmi_controller *ctrl,
+ u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
+{
+ struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+ u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+ const u8 *buf = __buf;
+ unsigned long flags;
+ u32 cmd, data;
+ int rc;
+ u8 op_code, i;
+
+ if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+ dev_err(&ctrl->dev,
+ "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+ SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+ return -EINVAL;
+ }
+
+ switch (opc) {
+ case SPMI_CMD_WRITE:
+ op_code = SPMI_CMD_REG_WRITE;
+ break;
+ case SPMI_CMD_EXT_WRITE:
+ op_code = SPMI_CMD_EXT_REG_WRITE;
+ break;
+ case SPMI_CMD_EXT_WRITEL:
+ op_code = SPMI_CMD_EXT_REG_WRITE_L;
+ break;
+ default:
+ dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
+ return -EINVAL;
+ }
+
+ cmd = SPMI_APB_SPMI_CMD_EN |
+ (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+ ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+ ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
+ ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
+
+ /* Write data to FIFOs */
+ spin_lock_irqsave(&spmi_controller->lock, flags);
+
+ for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+ data = 0;
+ if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+ memcpy(&data, buf, sizeof(data));
+ buf += sizeof(data);
+ } else {
+ memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
+ buf += (bc % SPMI_PER_DATAREG_BYTE);
+ }
+
+ writel((__force u32)cpu_to_be32(data),
+ spmi_controller->base + chnl_ofst +
+ SPMI_APB_SPMI_WDATA0_BASE_ADDR +
+ SPMI_PER_DATAREG_BYTE * i);
+ }
+
+ /* Start the transaction */
+ writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+ rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+ spmi_controller->base, slave_id,
+ slave_addr);
+ spin_unlock_irqrestore(&spmi_controller->lock, flags);
+
+ if (rc)
+ dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
+ opc, slave_id, slave_addr, bc);
+ else
+ dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
+ __func__, slave_id, slave_addr, (int)bc, __buf);
+
+ return rc;
+}
+
+static int spmi_controller_probe(struct platform_device *pdev)
+{
+ struct spmi_controller_dev *spmi_controller;
+ struct spmi_controller *ctrl;
+ struct resource *iores;
+ int ret;
+
+ ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+ if (!ctrl) {
+ dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
+ return -ENOMEM;
+ }
+ spmi_controller = spmi_controller_get_drvdata(ctrl);
+ spmi_controller->controller = ctrl;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores) {
+ dev_err(&pdev->dev, "can not get resource!\n");
+ return -EINVAL;
+ }
+
+ spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
+ resource_size(iores));
+ if (!spmi_controller->base) {
+ dev_err(&pdev->dev, "can not remap base addr!\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
+ &spmi_controller->channel);
+ if (ret) {
+ dev_err(&pdev->dev, "can not get channel\n");
+ return -ENODEV;
+ }
+
+ platform_set_drvdata(pdev, spmi_controller);
+ dev_set_drvdata(&ctrl->dev, spmi_controller);
+
+ spin_lock_init(&spmi_controller->lock);
+
+ ctrl->nr = spmi_controller->channel;
+ ctrl->dev.parent = pdev->dev.parent;
+ ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
+
+ /* Callbacks */
+ ctrl->read_cmd = spmi_read_cmd;
+ ctrl->write_cmd = spmi_write_cmd;
+
+ ret = spmi_controller_add(ctrl);
+ if (ret)
+ dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
+
+ return ret;
+}
+
+static int spmi_del_controller(struct platform_device *pdev)
+{
+ struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+ spmi_controller_remove(ctrl);
+ kfree(ctrl);
+ return 0;
+}
+
+static const struct of_device_id spmi_controller_match_table[] = {
+ {
+ .compatible = "hisilicon,kirin970-spmi-controller",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
+
+static struct platform_driver spmi_controller_driver = {
+ .probe = spmi_controller_probe,
+ .remove = spmi_del_controller,
+ .driver = {
+ .name = "hisi_spmi_controller",
+ .of_match_table = spmi_controller_match_table,
+ },
+};
+
+static int __init spmi_controller_init(void)
+{
+ return platform_driver_register(&spmi_controller_driver);
+}
+postcore_initcall(spmi_controller_init);
+
+static void __exit spmi_controller_exit(void)
+{
+ platform_driver_unregister(&spmi_controller_driver);
+}
+module_exit(spmi_controller_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:spmi_controller");
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index 0e97b5b9a56a..69392e42cd0d 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,16 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-# to be placed at drivers/spmi
-config SPMI_HISI3670
- tristate "Hisilicon 3670 SPMI Controller"
- select IRQ_DOMAIN_HIERARCHY
- depends on HAS_IOMEM
- depends on SPMI
- help
- If you say yes to this option, support will be included for the
- built-in SPMI PMIC Arbiter interface on Hisilicon 3670
- processors.
-
# to be placed at drivers/mfd
config MFD_HI6421_SPMI
tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 9371dcc3d35b..347880fd378f 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c
deleted file mode 100644
index 4be2344ad7b5..000000000000
--- a/drivers/staging/hikey9xx/hisi-spmi-controller.c
+++ /dev/null
@@ -1,358 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-/*
- * SPMI register addr
- */
-#define SPMI_CHANNEL_OFFSET 0x0300
-#define SPMI_SLAVE_OFFSET 0x20
-
-#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100
-
-#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104
-#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108
-#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c
-#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110
-
-#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200
-
-#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204
-#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208
-#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c
-#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210
-
-#define SPMI_PER_DATAREG_BYTE 4
-/*
- * SPMI cmd register
- */
-#define SPMI_APB_SPMI_CMD_EN BIT(31)
-#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24
-#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20
-#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16
-#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0
-
-/* Command Opcodes */
-
-enum spmi_controller_cmd_op_code {
- SPMI_CMD_REG_ZERO_WRITE = 0,
- SPMI_CMD_REG_WRITE = 1,
- SPMI_CMD_REG_READ = 2,
- SPMI_CMD_EXT_REG_WRITE = 3,
- SPMI_CMD_EXT_REG_READ = 4,
- SPMI_CMD_EXT_REG_WRITE_L = 5,
- SPMI_CMD_EXT_REG_READ_L = 6,
- SPMI_CMD_REG_RESET = 7,
- SPMI_CMD_REG_SLEEP = 8,
- SPMI_CMD_REG_SHUTDOWN = 9,
- SPMI_CMD_REG_WAKEUP = 10,
-};
-
-/*
- * SPMI status register
- */
-#define SPMI_APB_TRANS_DONE BIT(0)
-#define SPMI_APB_TRANS_FAIL BIT(2)
-
-/* Command register fields */
-#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16
-
-/* Maximum number of support PMIC peripherals */
-#define SPMI_CONTROLLER_TIMEOUT_US 1000
-#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16
-
-struct spmi_controller_dev {
- struct spmi_controller *controller;
- struct device *dev;
- void __iomem *base;
- spinlock_t lock;
- u32 channel;
-};
-
-static int spmi_controller_wait_for_done(struct device *dev,
- struct spmi_controller_dev *ctrl_dev,
- void __iomem *base, u8 sid, u16 addr)
-{
- u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
- u32 status, offset;
-
- offset = SPMI_APB_SPMI_STATUS_BASE_ADDR;
- offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
-
- do {
- status = readl(base + offset);
-
- if (status & SPMI_APB_TRANS_DONE) {
- if (status & SPMI_APB_TRANS_FAIL) {
- dev_err(dev, "%s: transaction failed (0x%x)\n",
- __func__, status);
- return -EIO;
- }
- dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
- return 0;
- }
- udelay(1);
- } while (timeout--);
-
- dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
- return -ETIMEDOUT;
-}
-
-static int spmi_read_cmd(struct spmi_controller *ctrl,
- u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
-{
- struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
- u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
- unsigned long flags;
- u8 *buf = __buf;
- u32 cmd, data;
- int rc;
- u8 op_code, i;
-
- if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
- dev_err(&ctrl->dev,
- "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
- SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
- return -EINVAL;
- }
-
- switch (opc) {
- case SPMI_CMD_READ:
- op_code = SPMI_CMD_REG_READ;
- break;
- case SPMI_CMD_EXT_READ:
- op_code = SPMI_CMD_EXT_REG_READ;
- break;
- case SPMI_CMD_EXT_READL:
- op_code = SPMI_CMD_EXT_REG_READ_L;
- break;
- default:
- dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
- return -EINVAL;
- }
-
- cmd = SPMI_APB_SPMI_CMD_EN |
- (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
- ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
- ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */
- ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
-
- spin_lock_irqsave(&spmi_controller->lock, flags);
-
- writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
-
- rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
- spmi_controller->base, slave_id, slave_addr);
- if (rc)
- goto done;
-
- for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
- data = readl(spmi_controller->base + chnl_ofst +
- SPMI_SLAVE_OFFSET * slave_id +
- SPMI_APB_SPMI_RDATA0_BASE_ADDR +
- i * SPMI_PER_DATAREG_BYTE);
- data = be32_to_cpu((__force __be32)data);
- if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
- memcpy(buf, &data, sizeof(data));
- buf += sizeof(data);
- } else {
- memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
- buf += (bc % SPMI_PER_DATAREG_BYTE);
- }
- }
-
-done:
- spin_unlock_irqrestore(&spmi_controller->lock, flags);
- if (rc)
- dev_err(&ctrl->dev,
- "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
- opc, slave_id, slave_addr, bc + 1);
- else
- dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
- __func__, slave_id, slave_addr, (int)bc, __buf);
-
- return rc;
-}
-
-static int spmi_write_cmd(struct spmi_controller *ctrl,
- u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
-{
- struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
- u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
- const u8 *buf = __buf;
- unsigned long flags;
- u32 cmd, data;
- int rc;
- u8 op_code, i;
-
- if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
- dev_err(&ctrl->dev,
- "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
- SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
- return -EINVAL;
- }
-
- switch (opc) {
- case SPMI_CMD_WRITE:
- op_code = SPMI_CMD_REG_WRITE;
- break;
- case SPMI_CMD_EXT_WRITE:
- op_code = SPMI_CMD_EXT_REG_WRITE;
- break;
- case SPMI_CMD_EXT_WRITEL:
- op_code = SPMI_CMD_EXT_REG_WRITE_L;
- break;
- default:
- dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
- return -EINVAL;
- }
-
- cmd = SPMI_APB_SPMI_CMD_EN |
- (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
- ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
- ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
- ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
-
- /* Write data to FIFOs */
- spin_lock_irqsave(&spmi_controller->lock, flags);
-
- for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
- data = 0;
- if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
- memcpy(&data, buf, sizeof(data));
- buf += sizeof(data);
- } else {
- memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
- buf += (bc % SPMI_PER_DATAREG_BYTE);
- }
-
- writel((__force u32)cpu_to_be32(data),
- spmi_controller->base + chnl_ofst +
- SPMI_APB_SPMI_WDATA0_BASE_ADDR +
- SPMI_PER_DATAREG_BYTE * i);
- }
-
- /* Start the transaction */
- writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
-
- rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
- spmi_controller->base, slave_id,
- slave_addr);
- spin_unlock_irqrestore(&spmi_controller->lock, flags);
-
- if (rc)
- dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
- opc, slave_id, slave_addr, bc);
- else
- dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
- __func__, slave_id, slave_addr, (int)bc, __buf);
-
- return rc;
-}
-
-static int spmi_controller_probe(struct platform_device *pdev)
-{
- struct spmi_controller_dev *spmi_controller;
- struct spmi_controller *ctrl;
- struct resource *iores;
- int ret;
-
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
- if (!ctrl) {
- dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
- return -ENOMEM;
- }
- spmi_controller = spmi_controller_get_drvdata(ctrl);
- spmi_controller->controller = ctrl;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores) {
- dev_err(&pdev->dev, "can not get resource!\n");
- return -EINVAL;
- }
-
- spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
- resource_size(iores));
- if (!spmi_controller->base) {
- dev_err(&pdev->dev, "can not remap base addr!\n");
- return -EADDRNOTAVAIL;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
- &spmi_controller->channel);
- if (ret) {
- dev_err(&pdev->dev, "can not get channel\n");
- return -ENODEV;
- }
-
- platform_set_drvdata(pdev, spmi_controller);
- dev_set_drvdata(&ctrl->dev, spmi_controller);
-
- spin_lock_init(&spmi_controller->lock);
-
- ctrl->nr = spmi_controller->channel;
- ctrl->dev.parent = pdev->dev.parent;
- ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
-
- /* Callbacks */
- ctrl->read_cmd = spmi_read_cmd;
- ctrl->write_cmd = spmi_write_cmd;
-
- ret = spmi_controller_add(ctrl);
- if (ret)
- dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
-
- return ret;
-}
-
-static int spmi_del_controller(struct platform_device *pdev)
-{
- struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-
- spmi_controller_remove(ctrl);
- kfree(ctrl);
- return 0;
-}
-
-static const struct of_device_id spmi_controller_match_table[] = {
- {
- .compatible = "hisilicon,kirin970-spmi-controller",
- },
- {}
-};
-MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
-
-static struct platform_driver spmi_controller_driver = {
- .probe = spmi_controller_probe,
- .remove = spmi_del_controller,
- .driver = {
- .name = "hisi_spmi_controller",
- .of_match_table = spmi_controller_match_table,
- },
-};
-
-static int __init spmi_controller_init(void)
-{
- return platform_driver_register(&spmi_controller_driver);
-}
-postcore_initcall(spmi_controller_init);
-
-static void __exit spmi_controller_exit(void)
-{
- platform_driver_unregister(&spmi_controller_driver);
-}
-module_exit(spmi_controller_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:spmi_controller");
diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
deleted file mode 100644
index 21f68a9c2df1..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
+++ /dev/null
@@ -1,75 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: HiSilicon SPMI controller
-
-maintainers:
- - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |
- The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
- It is a MIPI System Power Management (SPMI) controller.
-
- The PMIC part is provided by
- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-properties:
- $nodename:
- pattern: "spmi@[0-9a-f]"
-
- compatible:
- const: hisilicon,kirin970-spmi-controller
-
- reg:
- maxItems: 1
-
- "#address-cells":
- const: 2
-
- "#size-cells":
- const: 0
-
- spmi-channel:
- description: |
- number of the Kirin 970 SPMI channel where the SPMI devices are connected.
-
-required:
- - compatible
- - reg
- - spmi-channel
- - "#address-cells"
- - "#size-cells"
-
-patternProperties:
- "^pmic@[0-9a-f]$":
- description: |
- PMIC properties, which are specific to the used SPMI PMIC device(s).
- When used in combination with HiSilicon 6421v600, the properties
- are documented at
- drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
-
-additionalProperties: false
-
-examples:
- - |
- bus {
- #address-cells = <2>;
- #size-cells = <2>;
-
- spmi: spmi@fff24000 {
- compatible = "hisilicon,kirin970-spmi-controller";
- #address-cells = <2>;
- #size-cells = <0>;
- status = "ok";
- reg = <0x0 0xfff24000 0x0 0x1000>;
- spmi-channel = <2>;
-
- pmic@0 {
- reg = <0 0>;
- /* pmic properties */
- };
- };
- };
--
2.29.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging
2021-01-19 16:10 ` [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging Mauro Carvalho Chehab
@ 2021-02-05 22:19 ` Rob Herring
2021-03-25 13:47 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 10+ messages in thread
From: Rob Herring @ 2021-02-05 22:19 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mark Brown, Lee Jones, Colin Ian King, Dan Carpenter,
Greg Kroah-Hartman, Mayulong, Stephen Boyd, YueHaibing, devel,
devicetree, linux-arm-msm, linux-kernel
On Tue, Jan 19, 2021 at 05:10:43PM +0100, Mauro Carvalho Chehab wrote:
> The Hisilicon 6421v600 SPMI driver is ready for mainstream.
>
> So, move it from staging.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> .../spmi/hisilicon,hisi-spmi-controller.yaml | 75 ++++
> MAINTAINERS | 7 +
> drivers/spmi/Kconfig | 9 +
> drivers/spmi/Makefile | 1 +
> drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++++++++++
> drivers/staging/hikey9xx/Kconfig | 11 -
> drivers/staging/hikey9xx/Makefile | 1 -
> .../staging/hikey9xx/hisi-spmi-controller.c | 358 ------------------
> .../hisilicon,hisi-spmi-controller.yaml | 75 ----
> 9 files changed, 450 insertions(+), 445 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> create mode 100644 drivers/spmi/hisi-spmi-controller.c
> delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
> delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
>
> diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> new file mode 100644
> index 000000000000..21f68a9c2df1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> @@ -0,0 +1,75 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HiSilicon SPMI controller
> +
> +maintainers:
> + - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +
> +description: |
> + The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
> + It is a MIPI System Power Management (SPMI) controller.
> +
> + The PMIC part is provided by
> + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> +
> +properties:
> + $nodename:
> + pattern: "spmi@[0-9a-f]"
> +
> + compatible:
> + const: hisilicon,kirin970-spmi-controller
'-controller' is kind of redundant.
> +
> + reg:
> + maxItems: 1
> +
> + "#address-cells":
> + const: 2
> +
> + "#size-cells":
> + const: 0
These 2 are covered by spmi.yaml
> +
> + spmi-channel:
> + description: |
> + number of the Kirin 970 SPMI channel where the SPMI devices are connected.
Common to SPMI? If not, needs a vendor prefix.
Type? Range of values?
> +
> +required:
> + - compatible
> + - reg
> + - spmi-channel
> + - "#address-cells"
> + - "#size-cells"
Covered by spmi.yaml.
> +
> +patternProperties:
> + "^pmic@[0-9a-f]$":
Presumably you could have something besides a PMIC.
> + description: |
> + PMIC properties, which are specific to the used SPMI PMIC device(s).
> + When used in combination with HiSilicon 6421v600, the properties
> + are documented at
> + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + bus {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + spmi: spmi@fff24000 {
> + compatible = "hisilicon,kirin970-spmi-controller";
> + #address-cells = <2>;
> + #size-cells = <0>;
> + status = "ok";
Drop status.
> + reg = <0x0 0xfff24000 0x0 0x1000>;
> + spmi-channel = <2>;
> +
> + pmic@0 {
> + reg = <0 0>;
> + /* pmic properties */
> + };
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8d858e8d5a52..85e5b6ab57ca 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7999,6 +7999,13 @@ F: drivers/crypto/hisilicon/sec2/sec_crypto.c
> F: drivers/crypto/hisilicon/sec2/sec_crypto.h
> F: drivers/crypto/hisilicon/sec2/sec_main.c
>
> +HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970
> +M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +L: linux-kernel@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> +F: drivers/spmi/hisi-spmi-controller.c
> +
> HISILICON STAGING DRIVERS FOR HIKEY 960/970
> M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> L: devel@driverdev.osuosl.org
> diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
> index a53bad541f1a..2874b6c26028 100644
> --- a/drivers/spmi/Kconfig
> +++ b/drivers/spmi/Kconfig
> @@ -11,6 +11,15 @@ menuconfig SPMI
>
> if SPMI
>
> +config SPMI_HISI3670
> + tristate "Hisilicon 3670 SPMI Controller"
> + select IRQ_DOMAIN_HIERARCHY
> + depends on HAS_IOMEM
> + help
> + If you say yes to this option, support will be included for the
> + built-in SPMI PMIC Arbiter interface on Hisilicon 3670
> + processors.
> +
> config SPMI_MSM_PMIC_ARB
> tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
> select IRQ_DOMAIN_HIERARCHY
> diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
> index 55a94cadeffe..6e092e6f290c 100644
> --- a/drivers/spmi/Makefile
> +++ b/drivers/spmi/Makefile
> @@ -4,4 +4,5 @@
> #
> obj-$(CONFIG_SPMI) += spmi.o
>
> +obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
> obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
> diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
> new file mode 100644
> index 000000000000..4be2344ad7b5
> --- /dev/null
> +++ b/drivers/spmi/hisi-spmi-controller.c
> @@ -0,0 +1,358 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>
> +#include <linux/spmi.h>
> +
> +/*
> + * SPMI register addr
> + */
> +#define SPMI_CHANNEL_OFFSET 0x0300
> +#define SPMI_SLAVE_OFFSET 0x20
> +
> +#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100
> +
> +#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104
> +#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108
> +#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c
> +#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110
> +
> +#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200
> +
> +#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204
> +#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208
> +#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c
> +#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210
> +
> +#define SPMI_PER_DATAREG_BYTE 4
> +/*
> + * SPMI cmd register
> + */
> +#define SPMI_APB_SPMI_CMD_EN BIT(31)
> +#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24
> +#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20
> +#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16
> +#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0
> +
> +/* Command Opcodes */
> +
> +enum spmi_controller_cmd_op_code {
> + SPMI_CMD_REG_ZERO_WRITE = 0,
> + SPMI_CMD_REG_WRITE = 1,
> + SPMI_CMD_REG_READ = 2,
> + SPMI_CMD_EXT_REG_WRITE = 3,
> + SPMI_CMD_EXT_REG_READ = 4,
> + SPMI_CMD_EXT_REG_WRITE_L = 5,
> + SPMI_CMD_EXT_REG_READ_L = 6,
> + SPMI_CMD_REG_RESET = 7,
> + SPMI_CMD_REG_SLEEP = 8,
> + SPMI_CMD_REG_SHUTDOWN = 9,
> + SPMI_CMD_REG_WAKEUP = 10,
> +};
> +
> +/*
> + * SPMI status register
> + */
> +#define SPMI_APB_TRANS_DONE BIT(0)
> +#define SPMI_APB_TRANS_FAIL BIT(2)
> +
> +/* Command register fields */
> +#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16
> +
> +/* Maximum number of support PMIC peripherals */
> +#define SPMI_CONTROLLER_TIMEOUT_US 1000
> +#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16
> +
> +struct spmi_controller_dev {
> + struct spmi_controller *controller;
> + struct device *dev;
> + void __iomem *base;
> + spinlock_t lock;
> + u32 channel;
> +};
> +
> +static int spmi_controller_wait_for_done(struct device *dev,
> + struct spmi_controller_dev *ctrl_dev,
> + void __iomem *base, u8 sid, u16 addr)
> +{
> + u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
> + u32 status, offset;
> +
> + offset = SPMI_APB_SPMI_STATUS_BASE_ADDR;
> + offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
> +
> + do {
> + status = readl(base + offset);
> +
> + if (status & SPMI_APB_TRANS_DONE) {
> + if (status & SPMI_APB_TRANS_FAIL) {
> + dev_err(dev, "%s: transaction failed (0x%x)\n",
> + __func__, status);
> + return -EIO;
> + }
> + dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
> + return 0;
> + }
> + udelay(1);
> + } while (timeout--);
> +
> + dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
> + return -ETIMEDOUT;
> +}
> +
> +static int spmi_read_cmd(struct spmi_controller *ctrl,
> + u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
> +{
> + struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> + u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> + unsigned long flags;
> + u8 *buf = __buf;
> + u32 cmd, data;
> + int rc;
> + u8 op_code, i;
> +
> + if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> + dev_err(&ctrl->dev,
> + "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
> + SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> + return -EINVAL;
> + }
> +
> + switch (opc) {
> + case SPMI_CMD_READ:
> + op_code = SPMI_CMD_REG_READ;
> + break;
> + case SPMI_CMD_EXT_READ:
> + op_code = SPMI_CMD_EXT_REG_READ;
> + break;
> + case SPMI_CMD_EXT_READL:
> + op_code = SPMI_CMD_EXT_REG_READ_L;
> + break;
> + default:
> + dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
> + return -EINVAL;
> + }
> +
> + cmd = SPMI_APB_SPMI_CMD_EN |
> + (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
> + ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
> + ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */
> + ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
> +
> + spin_lock_irqsave(&spmi_controller->lock, flags);
> +
> + writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
> +
> + rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
> + spmi_controller->base, slave_id, slave_addr);
> + if (rc)
> + goto done;
> +
> + for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
> + data = readl(spmi_controller->base + chnl_ofst +
> + SPMI_SLAVE_OFFSET * slave_id +
> + SPMI_APB_SPMI_RDATA0_BASE_ADDR +
> + i * SPMI_PER_DATAREG_BYTE);
> + data = be32_to_cpu((__force __be32)data);
> + if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
> + memcpy(buf, &data, sizeof(data));
> + buf += sizeof(data);
> + } else {
> + memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
> + buf += (bc % SPMI_PER_DATAREG_BYTE);
> + }
> + }
> +
> +done:
> + spin_unlock_irqrestore(&spmi_controller->lock, flags);
> + if (rc)
> + dev_err(&ctrl->dev,
> + "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
> + opc, slave_id, slave_addr, bc + 1);
> + else
> + dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
> + __func__, slave_id, slave_addr, (int)bc, __buf);
> +
> + return rc;
> +}
> +
> +static int spmi_write_cmd(struct spmi_controller *ctrl,
> + u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
> +{
> + struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> + u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> + const u8 *buf = __buf;
> + unsigned long flags;
> + u32 cmd, data;
> + int rc;
> + u8 op_code, i;
> +
> + if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> + dev_err(&ctrl->dev,
> + "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
> + SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> + return -EINVAL;
> + }
> +
> + switch (opc) {
> + case SPMI_CMD_WRITE:
> + op_code = SPMI_CMD_REG_WRITE;
> + break;
> + case SPMI_CMD_EXT_WRITE:
> + op_code = SPMI_CMD_EXT_REG_WRITE;
> + break;
> + case SPMI_CMD_EXT_WRITEL:
> + op_code = SPMI_CMD_EXT_REG_WRITE_L;
> + break;
> + default:
> + dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
> + return -EINVAL;
> + }
> +
> + cmd = SPMI_APB_SPMI_CMD_EN |
> + (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
> + ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
> + ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
> + ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
> +
> + /* Write data to FIFOs */
> + spin_lock_irqsave(&spmi_controller->lock, flags);
> +
> + for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
> + data = 0;
> + if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
> + memcpy(&data, buf, sizeof(data));
> + buf += sizeof(data);
> + } else {
> + memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
> + buf += (bc % SPMI_PER_DATAREG_BYTE);
> + }
> +
> + writel((__force u32)cpu_to_be32(data),
> + spmi_controller->base + chnl_ofst +
> + SPMI_APB_SPMI_WDATA0_BASE_ADDR +
> + SPMI_PER_DATAREG_BYTE * i);
> + }
> +
> + /* Start the transaction */
> + writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
> +
> + rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
> + spmi_controller->base, slave_id,
> + slave_addr);
> + spin_unlock_irqrestore(&spmi_controller->lock, flags);
> +
> + if (rc)
> + dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
> + opc, slave_id, slave_addr, bc);
> + else
> + dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
> + __func__, slave_id, slave_addr, (int)bc, __buf);
> +
> + return rc;
> +}
> +
> +static int spmi_controller_probe(struct platform_device *pdev)
> +{
> + struct spmi_controller_dev *spmi_controller;
> + struct spmi_controller *ctrl;
> + struct resource *iores;
> + int ret;
> +
> + ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
> + if (!ctrl) {
> + dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
> + return -ENOMEM;
> + }
> + spmi_controller = spmi_controller_get_drvdata(ctrl);
> + spmi_controller->controller = ctrl;
> +
> + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!iores) {
> + dev_err(&pdev->dev, "can not get resource!\n");
> + return -EINVAL;
> + }
> +
> + spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
> + resource_size(iores));
> + if (!spmi_controller->base) {
> + dev_err(&pdev->dev, "can not remap base addr!\n");
> + return -EADDRNOTAVAIL;
> + }
> +
> + ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
> + &spmi_controller->channel);
> + if (ret) {
> + dev_err(&pdev->dev, "can not get channel\n");
> + return -ENODEV;
> + }
> +
> + platform_set_drvdata(pdev, spmi_controller);
> + dev_set_drvdata(&ctrl->dev, spmi_controller);
> +
> + spin_lock_init(&spmi_controller->lock);
> +
> + ctrl->nr = spmi_controller->channel;
> + ctrl->dev.parent = pdev->dev.parent;
> + ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
> +
> + /* Callbacks */
> + ctrl->read_cmd = spmi_read_cmd;
> + ctrl->write_cmd = spmi_write_cmd;
> +
> + ret = spmi_controller_add(ctrl);
> + if (ret)
> + dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
> +
> + return ret;
> +}
> +
> +static int spmi_del_controller(struct platform_device *pdev)
> +{
> + struct spmi_controller *ctrl = platform_get_drvdata(pdev);
> +
> + spmi_controller_remove(ctrl);
> + kfree(ctrl);
> + return 0;
> +}
> +
> +static const struct of_device_id spmi_controller_match_table[] = {
> + {
> + .compatible = "hisilicon,kirin970-spmi-controller",
> + },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
> +
> +static struct platform_driver spmi_controller_driver = {
> + .probe = spmi_controller_probe,
> + .remove = spmi_del_controller,
> + .driver = {
> + .name = "hisi_spmi_controller",
> + .of_match_table = spmi_controller_match_table,
> + },
> +};
> +
> +static int __init spmi_controller_init(void)
> +{
> + return platform_driver_register(&spmi_controller_driver);
> +}
> +postcore_initcall(spmi_controller_init);
> +
> +static void __exit spmi_controller_exit(void)
> +{
> + platform_driver_unregister(&spmi_controller_driver);
> +}
> +module_exit(spmi_controller_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_VERSION("1.0");
> +MODULE_ALIAS("platform:spmi_controller");
> diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
> index 0e97b5b9a56a..69392e42cd0d 100644
> --- a/drivers/staging/hikey9xx/Kconfig
> +++ b/drivers/staging/hikey9xx/Kconfig
> @@ -1,16 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0
>
> -# to be placed at drivers/spmi
> -config SPMI_HISI3670
> - tristate "Hisilicon 3670 SPMI Controller"
> - select IRQ_DOMAIN_HIERARCHY
> - depends on HAS_IOMEM
> - depends on SPMI
> - help
> - If you say yes to this option, support will be included for the
> - built-in SPMI PMIC Arbiter interface on Hisilicon 3670
> - processors.
> -
> # to be placed at drivers/mfd
> config MFD_HI6421_SPMI
> tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
> diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
> index 9371dcc3d35b..347880fd378f 100644
> --- a/drivers/staging/hikey9xx/Makefile
> +++ b/drivers/staging/hikey9xx/Makefile
> @@ -1,5 +1,4 @@
> # SPDX-License-Identifier: GPL-2.0
>
> -obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
> obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
> obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
> diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c
> deleted file mode 100644
> index 4be2344ad7b5..000000000000
> --- a/drivers/staging/hikey9xx/hisi-spmi-controller.c
> +++ /dev/null
> @@ -1,358 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -
> -#include <linux/delay.h>
> -#include <linux/err.h>
> -#include <linux/interrupt.h>
> -#include <linux/io.h>
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/of.h>
> -#include <linux/platform_device.h>
> -#include <linux/seq_file.h>
> -#include <linux/slab.h>
> -#include <linux/spmi.h>
> -
> -/*
> - * SPMI register addr
> - */
> -#define SPMI_CHANNEL_OFFSET 0x0300
> -#define SPMI_SLAVE_OFFSET 0x20
> -
> -#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100
> -
> -#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104
> -#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108
> -#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c
> -#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110
> -
> -#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200
> -
> -#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204
> -#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208
> -#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c
> -#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210
> -
> -#define SPMI_PER_DATAREG_BYTE 4
> -/*
> - * SPMI cmd register
> - */
> -#define SPMI_APB_SPMI_CMD_EN BIT(31)
> -#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24
> -#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20
> -#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16
> -#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0
> -
> -/* Command Opcodes */
> -
> -enum spmi_controller_cmd_op_code {
> - SPMI_CMD_REG_ZERO_WRITE = 0,
> - SPMI_CMD_REG_WRITE = 1,
> - SPMI_CMD_REG_READ = 2,
> - SPMI_CMD_EXT_REG_WRITE = 3,
> - SPMI_CMD_EXT_REG_READ = 4,
> - SPMI_CMD_EXT_REG_WRITE_L = 5,
> - SPMI_CMD_EXT_REG_READ_L = 6,
> - SPMI_CMD_REG_RESET = 7,
> - SPMI_CMD_REG_SLEEP = 8,
> - SPMI_CMD_REG_SHUTDOWN = 9,
> - SPMI_CMD_REG_WAKEUP = 10,
> -};
> -
> -/*
> - * SPMI status register
> - */
> -#define SPMI_APB_TRANS_DONE BIT(0)
> -#define SPMI_APB_TRANS_FAIL BIT(2)
> -
> -/* Command register fields */
> -#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16
> -
> -/* Maximum number of support PMIC peripherals */
> -#define SPMI_CONTROLLER_TIMEOUT_US 1000
> -#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16
> -
> -struct spmi_controller_dev {
> - struct spmi_controller *controller;
> - struct device *dev;
> - void __iomem *base;
> - spinlock_t lock;
> - u32 channel;
> -};
> -
> -static int spmi_controller_wait_for_done(struct device *dev,
> - struct spmi_controller_dev *ctrl_dev,
> - void __iomem *base, u8 sid, u16 addr)
> -{
> - u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
> - u32 status, offset;
> -
> - offset = SPMI_APB_SPMI_STATUS_BASE_ADDR;
> - offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
> -
> - do {
> - status = readl(base + offset);
> -
> - if (status & SPMI_APB_TRANS_DONE) {
> - if (status & SPMI_APB_TRANS_FAIL) {
> - dev_err(dev, "%s: transaction failed (0x%x)\n",
> - __func__, status);
> - return -EIO;
> - }
> - dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
> - return 0;
> - }
> - udelay(1);
> - } while (timeout--);
> -
> - dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
> - return -ETIMEDOUT;
> -}
> -
> -static int spmi_read_cmd(struct spmi_controller *ctrl,
> - u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
> -{
> - struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> - u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> - unsigned long flags;
> - u8 *buf = __buf;
> - u32 cmd, data;
> - int rc;
> - u8 op_code, i;
> -
> - if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> - dev_err(&ctrl->dev,
> - "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
> - SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> - return -EINVAL;
> - }
> -
> - switch (opc) {
> - case SPMI_CMD_READ:
> - op_code = SPMI_CMD_REG_READ;
> - break;
> - case SPMI_CMD_EXT_READ:
> - op_code = SPMI_CMD_EXT_REG_READ;
> - break;
> - case SPMI_CMD_EXT_READL:
> - op_code = SPMI_CMD_EXT_REG_READ_L;
> - break;
> - default:
> - dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
> - return -EINVAL;
> - }
> -
> - cmd = SPMI_APB_SPMI_CMD_EN |
> - (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
> - ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
> - ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */
> - ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
> -
> - spin_lock_irqsave(&spmi_controller->lock, flags);
> -
> - writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
> -
> - rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
> - spmi_controller->base, slave_id, slave_addr);
> - if (rc)
> - goto done;
> -
> - for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
> - data = readl(spmi_controller->base + chnl_ofst +
> - SPMI_SLAVE_OFFSET * slave_id +
> - SPMI_APB_SPMI_RDATA0_BASE_ADDR +
> - i * SPMI_PER_DATAREG_BYTE);
> - data = be32_to_cpu((__force __be32)data);
> - if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
> - memcpy(buf, &data, sizeof(data));
> - buf += sizeof(data);
> - } else {
> - memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
> - buf += (bc % SPMI_PER_DATAREG_BYTE);
> - }
> - }
> -
> -done:
> - spin_unlock_irqrestore(&spmi_controller->lock, flags);
> - if (rc)
> - dev_err(&ctrl->dev,
> - "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
> - opc, slave_id, slave_addr, bc + 1);
> - else
> - dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
> - __func__, slave_id, slave_addr, (int)bc, __buf);
> -
> - return rc;
> -}
> -
> -static int spmi_write_cmd(struct spmi_controller *ctrl,
> - u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
> -{
> - struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
> - u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
> - const u8 *buf = __buf;
> - unsigned long flags;
> - u32 cmd, data;
> - int rc;
> - u8 op_code, i;
> -
> - if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
> - dev_err(&ctrl->dev,
> - "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
> - SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
> - return -EINVAL;
> - }
> -
> - switch (opc) {
> - case SPMI_CMD_WRITE:
> - op_code = SPMI_CMD_REG_WRITE;
> - break;
> - case SPMI_CMD_EXT_WRITE:
> - op_code = SPMI_CMD_EXT_REG_WRITE;
> - break;
> - case SPMI_CMD_EXT_WRITEL:
> - op_code = SPMI_CMD_EXT_REG_WRITE_L;
> - break;
> - default:
> - dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
> - return -EINVAL;
> - }
> -
> - cmd = SPMI_APB_SPMI_CMD_EN |
> - (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
> - ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
> - ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
> - ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
> -
> - /* Write data to FIFOs */
> - spin_lock_irqsave(&spmi_controller->lock, flags);
> -
> - for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
> - data = 0;
> - if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
> - memcpy(&data, buf, sizeof(data));
> - buf += sizeof(data);
> - } else {
> - memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
> - buf += (bc % SPMI_PER_DATAREG_BYTE);
> - }
> -
> - writel((__force u32)cpu_to_be32(data),
> - spmi_controller->base + chnl_ofst +
> - SPMI_APB_SPMI_WDATA0_BASE_ADDR +
> - SPMI_PER_DATAREG_BYTE * i);
> - }
> -
> - /* Start the transaction */
> - writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
> -
> - rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
> - spmi_controller->base, slave_id,
> - slave_addr);
> - spin_unlock_irqrestore(&spmi_controller->lock, flags);
> -
> - if (rc)
> - dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
> - opc, slave_id, slave_addr, bc);
> - else
> - dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n",
> - __func__, slave_id, slave_addr, (int)bc, __buf);
> -
> - return rc;
> -}
> -
> -static int spmi_controller_probe(struct platform_device *pdev)
> -{
> - struct spmi_controller_dev *spmi_controller;
> - struct spmi_controller *ctrl;
> - struct resource *iores;
> - int ret;
> -
> - ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
> - if (!ctrl) {
> - dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
> - return -ENOMEM;
> - }
> - spmi_controller = spmi_controller_get_drvdata(ctrl);
> - spmi_controller->controller = ctrl;
> -
> - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!iores) {
> - dev_err(&pdev->dev, "can not get resource!\n");
> - return -EINVAL;
> - }
> -
> - spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
> - resource_size(iores));
> - if (!spmi_controller->base) {
> - dev_err(&pdev->dev, "can not remap base addr!\n");
> - return -EADDRNOTAVAIL;
> - }
> -
> - ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel",
> - &spmi_controller->channel);
> - if (ret) {
> - dev_err(&pdev->dev, "can not get channel\n");
> - return -ENODEV;
> - }
> -
> - platform_set_drvdata(pdev, spmi_controller);
> - dev_set_drvdata(&ctrl->dev, spmi_controller);
> -
> - spin_lock_init(&spmi_controller->lock);
> -
> - ctrl->nr = spmi_controller->channel;
> - ctrl->dev.parent = pdev->dev.parent;
> - ctrl->dev.of_node = of_node_get(pdev->dev.of_node);
> -
> - /* Callbacks */
> - ctrl->read_cmd = spmi_read_cmd;
> - ctrl->write_cmd = spmi_write_cmd;
> -
> - ret = spmi_controller_add(ctrl);
> - if (ret)
> - dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret);
> -
> - return ret;
> -}
> -
> -static int spmi_del_controller(struct platform_device *pdev)
> -{
> - struct spmi_controller *ctrl = platform_get_drvdata(pdev);
> -
> - spmi_controller_remove(ctrl);
> - kfree(ctrl);
> - return 0;
> -}
> -
> -static const struct of_device_id spmi_controller_match_table[] = {
> - {
> - .compatible = "hisilicon,kirin970-spmi-controller",
> - },
> - {}
> -};
> -MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
> -
> -static struct platform_driver spmi_controller_driver = {
> - .probe = spmi_controller_probe,
> - .remove = spmi_del_controller,
> - .driver = {
> - .name = "hisi_spmi_controller",
> - .of_match_table = spmi_controller_match_table,
> - },
> -};
> -
> -static int __init spmi_controller_init(void)
> -{
> - return platform_driver_register(&spmi_controller_driver);
> -}
> -postcore_initcall(spmi_controller_init);
> -
> -static void __exit spmi_controller_exit(void)
> -{
> - platform_driver_unregister(&spmi_controller_driver);
> -}
> -module_exit(spmi_controller_exit);
> -
> -MODULE_LICENSE("GPL v2");
> -MODULE_VERSION("1.0");
> -MODULE_ALIAS("platform:spmi_controller");
> diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
> deleted file mode 100644
> index 21f68a9c2df1..000000000000
> --- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
> +++ /dev/null
> @@ -1,75 +0,0 @@
> -# SPDX-License-Identifier: GPL-2.0
> -%YAML 1.2
> ----
> -$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
> -$schema: http://devicetree.org/meta-schemas/core.yaml#
> -
> -title: HiSilicon SPMI controller
> -
> -maintainers:
> - - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> -
> -description: |
> - The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
> - It is a MIPI System Power Management (SPMI) controller.
> -
> - The PMIC part is provided by
> - drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> -
> -properties:
> - $nodename:
> - pattern: "spmi@[0-9a-f]"
> -
> - compatible:
> - const: hisilicon,kirin970-spmi-controller
> -
> - reg:
> - maxItems: 1
> -
> - "#address-cells":
> - const: 2
> -
> - "#size-cells":
> - const: 0
> -
> - spmi-channel:
> - description: |
> - number of the Kirin 970 SPMI channel where the SPMI devices are connected.
> -
> -required:
> - - compatible
> - - reg
> - - spmi-channel
> - - "#address-cells"
> - - "#size-cells"
> -
> -patternProperties:
> - "^pmic@[0-9a-f]$":
> - description: |
> - PMIC properties, which are specific to the used SPMI PMIC device(s).
> - When used in combination with HiSilicon 6421v600, the properties
> - are documented at
> - drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> -
> -additionalProperties: false
> -
> -examples:
> - - |
> - bus {
> - #address-cells = <2>;
> - #size-cells = <2>;
> -
> - spmi: spmi@fff24000 {
> - compatible = "hisilicon,kirin970-spmi-controller";
> - #address-cells = <2>;
> - #size-cells = <0>;
> - status = "ok";
> - reg = <0x0 0xfff24000 0x0 0x1000>;
> - spmi-channel = <2>;
> -
> - pmic@0 {
> - reg = <0 0>;
> - /* pmic properties */
> - };
> - };
> - };
> --
> 2.29.2
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging
2021-02-05 22:19 ` Rob Herring
@ 2021-03-25 13:47 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2021-03-25 13:47 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Brown, Lee Jones, Colin Ian King, Dan Carpenter,
Greg Kroah-Hartman, Mayulong, Stephen Boyd, YueHaibing, devel,
devicetree, linux-arm-msm, linux-kernel
Em Fri, 5 Feb 2021 16:19:47 -0600
Rob Herring <robh@kernel.org> escreveu:
> On Tue, Jan 19, 2021 at 05:10:43PM +0100, Mauro Carvalho Chehab wrote:
> > The Hisilicon 6421v600 SPMI driver is ready for mainstream.
> >
> > So, move it from staging.
> >
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > ---
> > .../spmi/hisilicon,hisi-spmi-controller.yaml | 75 ++++
> > MAINTAINERS | 7 +
> > drivers/spmi/Kconfig | 9 +
> > drivers/spmi/Makefile | 1 +
> > drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++++++++++
> > drivers/staging/hikey9xx/Kconfig | 11 -
> > drivers/staging/hikey9xx/Makefile | 1 -
> > .../staging/hikey9xx/hisi-spmi-controller.c | 358 ------------------
> > .../hisilicon,hisi-spmi-controller.yaml | 75 ----
> > 9 files changed, 450 insertions(+), 445 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> > create mode 100644 drivers/spmi/hisi-spmi-controller.c
> > delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c
> > delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> > new file mode 100644
> > index 000000000000..21f68a9c2df1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> > @@ -0,0 +1,75 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: HiSilicon SPMI controller
> > +
> > +maintainers:
> > + - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> > +
> > +description: |
> > + The HiSilicon SPMI BUS controller is found on some Kirin-based designs.
> > + It is a MIPI System Power Management (SPMI) controller.
> > +
> > + The PMIC part is provided by
> > + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> > +
> > +properties:
> > + $nodename:
> > + pattern: "spmi@[0-9a-f]"
> > +
> > + compatible:
> > + const: hisilicon,kirin970-spmi-controller
>
> '-controller' is kind of redundant.
Ok. Will drop it.
>
> > +
> > + reg:
> > + maxItems: 1
> > +
>
> > + "#address-cells":
> > + const: 2
> > +
> > + "#size-cells":
> > + const: 0
>
> These 2 are covered by spmi.yaml
Ok.
>
> > +
> > + spmi-channel:
> > + description: |
> > + number of the Kirin 970 SPMI channel where the SPMI devices are connected.
>
> Common to SPMI? If not, needs a vendor prefix.
That's an interesting question. My understanding is that this is not
vendor-specific, but maybe Stephen can give us more details.
The spmi.h header calls it "nr", and documents it at include/linux/spmi.h
as:
/**
* struct spmi_controller - interface to the SPMI master controller
* @dev: Driver model representation of the device.
* @nr: board-specific number identifier for this controller/bus
* @cmd: sends a non-data command sequence on the SPMI bus.
* @read_cmd: sends a register read command sequence on the SPMI bus.
* @write_cmd: sends a register write command sequence on the SPMI bus.
*/
There, it says that this is "board-specific number identifier".
Yet, as the SPMI is a serial bus with up to 4 masters (controller), I
suspect that the idea is to associate it with the master ID.
This is used on boards with multiple SoCs. See, for instance, slide 5 of:
https://www.mipi.org/sites/default/files/Bangalore-Qualcomm-SPMI-1.0-Multi-master-Verification.pdf
However, it is hard to know for sure, as no drivers use it, except by
Hikey 970 controller:
$ grep "\b\->nr\b" $(git grep -l spmi.h)
drivers/spmi/spmi.c: ida_simple_remove(&ctrl_ida, ctrl->nr);
drivers/spmi/spmi.c: dev_set_name(&sdev->dev, "%d-%02x", ctrl->nr, sdev->usid);
drivers/spmi/spmi.c: ctrl->nr = id;
drivers/spmi/spmi.c: ctrl->nr, &ctrl->dev);
drivers/staging/hikey9xx/hisi-spmi-controller.c: ctrl->nr = spmi_controller->channel;
>
> Type? Range of values?
The SPMI core defines it as "unsigned int". So, I would use:
$ref: /schemas/types.yaml#/definitions/uint32
as a type.
At the driver, this is used to calculate the channel offset with:
static int spmi_write_cmd(...) {
u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
...
writel((u32 __force)cpu_to_be32(data),
spmi_controller->base + chnl_ofst +
SPMI_APB_SPMI_WDATA0_BASE_ADDR +
SPMI_PER_DATAREG_BYTE * i);
...
}
As on both spmi.h and the Hikey 970 SPMI controller defines it as uint32,
it doesn't seem to be a good idea to put a range of values, specially
since we don't have the datasheets for this SoC.
>
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - spmi-channel
>
> > + - "#address-cells"
> > + - "#size-cells"
>
> Covered by spmi.yaml.
>
> > +
> > +patternProperties:
> > + "^pmic@[0-9a-f]$":
>
> Presumably you could have something besides a PMIC.
Hmm... SPMI means MIPI System Power Management Interface.
The MIPI says that [1]:
"The MIPI System Power Management Interface is a two-wire serial
interface that uses CMOS I/Os for the physical layer. The interface
connects the integrated power controller of a system-on-chip (SoC)
processor system with one or more power management IC voltage
regulation systems."
[1] https://www.mipi.org/specifications/system-power-management-interface
OK, as this is a serial bus, I guess one could abuse the interface
and add non-PMIC devices on it. Also, some future version of SPMI
might extend it to non-PMIC devices, but, IMO, if we ever add a
non-PMIC device, another patternProperties would be needed in order
to describe the other device types that could be connected to the PM bus.
>
> > + description: |
> > + PMIC properties, which are specific to the used SPMI PMIC device(s).
> > + When used in combination with HiSilicon 6421v600, the properties
> > + are documented at
> > + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + bus {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + spmi: spmi@fff24000 {
> > + compatible = "hisilicon,kirin970-spmi-controller";
> > + #address-cells = <2>;
> > + #size-cells = <0>;
> > + status = "ok";
>
> Drop status.
Ok.
>
> > + reg = <0x0 0xfff24000 0x0 0x1000>;
> > + spmi-channel = <2>;
> > +
> > + pmic@0 {
> > + reg = <0 0>;
> > + /* pmic properties */
> > + };
> > + };
> > + };
Thanks,
Mauro
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 18/21] mfd: hi6421-spmi-pmic: move driver from staging
2021-01-19 16:10 [PATCH v4 00/21] Move Hisilicon 6421v600 SPMI driver set out of staging Mauro Carvalho Chehab
2021-01-19 16:10 ` [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging Mauro Carvalho Chehab
@ 2021-01-19 16:10 ` Mauro Carvalho Chehab
2021-01-27 11:05 ` Lee Jones
` (2 more replies)
2021-01-19 16:10 ` [PATCH v4 20/21] dts: hisilicon: add support for USB3 on Hikey 970 Mauro Carvalho Chehab
2021-01-19 16:10 ` [PATCH v4 21/21] dts: hisilicon: add support for the PMIC found " Mauro Carvalho Chehab
3 siblings, 3 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2021-01-19 16:10 UTC (permalink / raw)
To: Mark Brown, Lee Jones
Cc: Mauro Carvalho Chehab, Greg Kroah-Hartman, Mayulong, Rob Herring,
devel, devicetree, linux-kernel
This driver is ready for mainstream. So, move it out of staging.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.../mfd/hisilicon,hi6421-spmi-pmic.yaml | 135 +++++++++
MAINTAINERS | 7 +
drivers/mfd/Kconfig | 15 +
drivers/mfd/Makefile | 1 +
drivers/mfd/hi6421-spmi-pmic.c | 281 ++++++++++++++++++
drivers/staging/hikey9xx/Kconfig | 16 -
drivers/staging/hikey9xx/Makefile | 1 -
drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 281 ------------------
.../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 135 ---------
9 files changed, 439 insertions(+), 433 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
new file mode 100644
index 000000000000..3b23ad56b31a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon 6421v600 SPMI PMIC
+
+maintainers:
+ - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+
+description: |
+ HiSilicon 6421v600 should be connected inside a MIPI System Power Management
+ (SPMI) bus. It provides interrupts and power supply.
+
+ The GPIO and interrupt settings are represented as part of the top-level PMIC
+ node.
+
+ The SPMI controller part is provided by
+ drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
+
+properties:
+ $nodename:
+ pattern: "pmic@[0-9a-f]"
+
+ compatible:
+ const: hisilicon,hi6421v600-spmi
+
+ reg:
+ maxItems: 1
+
+ '#interrupt-cells':
+ const: 2
+
+ interrupt-controller:
+ description:
+ Identify that the PMIC is capable of behaving as an interrupt controller.
+
+ gpios:
+ maxItems: 1
+
+ regulators:
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ '^ldo[0-9]+@[0-9a-f]$':
+ type: object
+
+ $ref: "/schemas/regulator/regulator.yaml#"
+
+required:
+ - compatible
+ - reg
+ - regulators
+
+additionalProperties: false
+
+examples:
+ - |
+ /* pmic properties */
+
+ pmic: pmic@0 {
+ compatible = "hisilicon,hi6421-spmi";
+ reg = <0 0>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ gpios = <&gpio28 0 0>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ldo3: LDO3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-boot-on;
+ };
+
+ ldo4: LDO4 {
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1725000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-boot-on;
+ };
+
+ ldo9: LDO9 {
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo15: LDO15 {
+ regulator-name = "ldo15";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo16: LDO16 {
+ regulator-name = "ldo16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ };
+
+ ldo17: LDO17 {
+ regulator-name = "ldo17";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo33: LDO33 {
+ regulator-name = "ldo33";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo34: LDO34 {
+ regulator-name = "ldo34";
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 85e5b6ab57ca..c5b36a58ede5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8006,6 +8006,13 @@ S: Maintained
F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
F: drivers/spmi/hisi-spmi-controller.c
+HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
+M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+F: drivers/mfd/hi6421-spmi-pmic.c
+
HISILICON STAGING DRIVERS FOR HIKEY 960/970
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
L: devel@driverdev.osuosl.org
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8b99a13669bf..c04c2f6be1d9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -509,6 +509,21 @@ config MFD_HI6421_PMIC
menus in order to enable them.
We communicate with the Hi6421 via memory-mapped I/O.
+config MFD_HI6421_SPMI
+ tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
+ depends on OF
+ depends on SPMI
+ select MFD_CORE
+ help
+ Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
+ multi-functions, such as regulators, RTC, codec, Coulomb counter,
+ etc.
+
+ This driver includes core APIs _only_. You have to select
+ individual components like voltage regulators under corresponding
+ menus in order to enable them.
+ We communicate with the Hi6421v600 via a SPMI bus.
+
config MFD_HI655X_PMIC
tristate "HiSilicon Hi655X series PMU/Codec IC"
depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1780019d2474..7744993c42bc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -233,6 +233,7 @@ obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
obj-$(CONFIG_MFD_IQS62X) += iqs62x.o
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
+obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
new file mode 100644
index 000000000000..99c4f3359f71
--- /dev/null
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Device driver for regulators in HISI PMIC IC
+//
+// Copyright (c) 2013 Linaro Ltd.
+// Copyright (c) 2011 Hisilicon.
+//
+// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/* 8-bit register offset in PMIC */
+#define HISI_MASK_STATE 0xff
+
+#define HISI_IRQ_ARRAY 2
+#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8)
+
+#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
+#define SOC_PMIC_IRQ0_ADDR 0x0212
+
+#define HISI_IRQ_KEY_NUM 0
+#define HISI_IRQ_KEY_VALUE 0xc0
+#define HISI_IRQ_KEY_DOWN 7
+#define HISI_IRQ_KEY_UP 6
+
+#define HISI_MASK_FIELD 0xFF
+#define HISI_BITS 8
+
+/*define the first group interrupt register number*/
+#define HISI_PMIC_FIRST_GROUP_INT_NUM 2
+
+static const struct mfd_cell hi6421v600_devs[] = {
+ { .name = "hi6421v600-regulator", },
+};
+
+static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
+{
+ struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)priv;
+ unsigned long pending;
+ unsigned int data;
+ int i, offset;
+
+ for (i = 0; i < HISI_IRQ_ARRAY; i++) {
+ regmap_read(pmic->map, offset, &data);
+ data &= HISI_MASK_FIELD;
+ if (data != 0)
+ pr_debug("data[%d]=0x%d\n\r", i, data);
+ regmap_write(pmic->map, i + SOC_PMIC_IRQ0_ADDR, data);
+
+ /* for_each_set_bit() macro requires unsigned long */
+ pending = data;
+
+ /* 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);
+ unsigned long flags;
+ unsigned int data;
+ u32 offset;
+
+ offset = (irqd_to_hwirq(d) >> 3);
+ offset += SOC_PMIC_IRQ_MASK_0_ADDR;
+
+ spin_lock_irqsave(&pmic->lock, flags);
+
+ regmap_read(pmic->map, offset, &data);
+ data |= (1 << (irqd_to_hwirq(d) & 0x07));
+ regmap_write(pmic->map, offset, data);
+ spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static void hi6421_spmi_irq_unmask(struct irq_data *d)
+{
+ struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+ unsigned long flags;
+
+ offset = (irqd_to_hwirq(d) >> 3);
+ offset += SOC_PMIC_IRQ_MASK_0_ADDR;
+
+ spin_lock_irqsave(&pmic->lock, flags);
+ regmap_read(pmic->map, offset, &data);
+ data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
+ regmap_write(pmic->map, offset, data);
+ spin_unlock_irqrestore(&pmic->lock, flags);
+}
+
+static struct irq_chip hi6421_spmi_pmu_irqchip = {
+ .name = "hisi-irq",
+ .irq_mask = hi6421_spmi_irq_mask,
+ .irq_unmask = hi6421_spmi_irq_unmask,
+ .irq_disable = hi6421_spmi_irq_mask,
+ .irq_enable = hi6421_spmi_irq_unmask,
+};
+
+static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct hi6421_spmi_pmic *pmic = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
+ handle_simple_irq, "hisi");
+ irq_set_chip_data(virq, pmic);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops hi6421_spmi_domain_ops = {
+ .map = hi6421_spmi_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
+{
+ int i;
+ unsigned int pending;
+
+ for (i = 0 ; i < HISI_IRQ_ARRAY; i++)
+ regmap_write(pmic->map, SOC_PMIC_IRQ_MASK_0_ADDR + i,
+ HISI_MASK_STATE);
+
+ for (i = 0 ; i < HISI_IRQ_ARRAY; i++) {
+ regmap_read(pmic->map, SOC_PMIC_IRQ0_ADDR + i, &pending);
+
+ pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
+ SOC_PMIC_IRQ0_ADDR + i, pending);
+ regmap_write(pmic->map, SOC_PMIC_IRQ0_ADDR + i,
+ HISI_MASK_STATE);
+ }
+}
+
+static const struct regmap_config spmi_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xffff,
+ .fast_io = true
+};
+
+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;
+ struct regmap *map;
+ unsigned int virq;
+ int ret, i;
+
+ pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ map = devm_regmap_init_spmi_ext(pdev, &spmi_regmap_config);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ spin_lock_init(&pmic->lock);
+
+ pmic->dev = dev;
+ pmic->map = map;
+
+ pmic->gpio = of_get_gpio(np, 0);
+ if (pmic->gpio < 0)
+ return pmic->gpio;
+
+ if (!gpio_is_valid(pmic->gpio))
+ return -EINVAL;
+
+ ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic");
+ if (ret < 0) {
+ dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
+ return ret;
+ }
+
+ pmic->irq = gpio_to_irq(pmic->gpio);
+
+ hi6421_spmi_pmic_irq_prc(pmic);
+
+ pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
+ if (!pmic->irqs)
+ goto irq_malloc;
+
+ pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
+ &hi6421_spmi_domain_ops, pmic);
+ if (!pmic->domain) {
+ dev_err(dev, "failed irq domain add simple!\n");
+ ret = -ENODEV;
+ goto irq_malloc;
+ }
+
+ for (i = 0; i < HISI_IRQ_NUM; i++) {
+ virq = irq_create_mapping(pmic->domain, i);
+ if (!virq) {
+ dev_err(dev, "Failed mapping hwirq\n");
+ ret = -ENOSPC;
+ goto irq_malloc;
+ }
+ pmic->irqs[i] = virq;
+ dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n",
+ __func__, i, pmic->irqs[i]);
+ }
+
+ ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
+ IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pmic", pmic);
+ if (ret < 0) {
+ dev_err(dev, "could not claim pmic IRQ: error %d\n", ret);
+ goto irq_malloc;
+ }
+
+ dev_set_drvdata(&pdev->dev, pmic);
+
+ /*
+ * The logic below will rely that the pmic is already stored at
+ * drvdata.
+ */
+ dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n",
+ pdev->dev.of_node);
+ ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
+ NULL, 0, NULL);
+ if (!ret)
+ return 0;
+
+ dev_err(dev, "Failed to add child devices: %d\n", ret);
+
+irq_malloc:
+ free_irq(pmic->irq, pmic);
+
+ return ret;
+}
+
+static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
+{
+ struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
+
+ free_irq(pmic->irq, pmic);
+}
+
+static const struct of_device_id pmic_spmi_id_table[] = {
+ { .compatible = "hisilicon,hi6421-spmi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
+
+static struct spmi_driver hi6421_spmi_pmic_driver = {
+ .driver = {
+ .name = "hi6421-spmi-pmic",
+ .of_match_table = pmic_spmi_id_table,
+ },
+ .probe = hi6421_spmi_pmic_probe,
+ .remove = hi6421_spmi_pmic_remove,
+};
+module_spmi_driver(hi6421_spmi_pmic_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
index 69392e42cd0d..1afb8648a2c4 100644
--- a/drivers/staging/hikey9xx/Kconfig
+++ b/drivers/staging/hikey9xx/Kconfig
@@ -1,21 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-# to be placed at drivers/mfd
-config MFD_HI6421_SPMI
- tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
- depends on OF
- depends on SPMI
- select MFD_CORE
- help
- Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
- multi-functions, such as regulators, RTC, codec, Coulomb counter,
- etc.
-
- This driver includes core APIs _only_. You have to select
- individual components like voltage regulators under corresponding
- menus in order to enable them.
- We communicate with the Hi6421v600 via a SPMI bus.
-
# to be placed at drivers/regulator
config REGULATOR_HI6421V600
tristate "HiSilicon Hi6421v600 PMIC voltage regulator support"
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
index 347880fd378f..4d63184e6086 100644
--- a/drivers/staging/hikey9xx/Makefile
+++ b/drivers/staging/hikey9xx/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o
diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
deleted file mode 100644
index 99c4f3359f71..000000000000
--- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
+++ /dev/null
@@ -1,281 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Device driver for regulators in HISI PMIC IC
-//
-// Copyright (c) 2013 Linaro Ltd.
-// Copyright (c) 2011 Hisilicon.
-//
-// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/hi6421-spmi-pmic.h>
-#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-/* 8-bit register offset in PMIC */
-#define HISI_MASK_STATE 0xff
-
-#define HISI_IRQ_ARRAY 2
-#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8)
-
-#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
-#define SOC_PMIC_IRQ0_ADDR 0x0212
-
-#define HISI_IRQ_KEY_NUM 0
-#define HISI_IRQ_KEY_VALUE 0xc0
-#define HISI_IRQ_KEY_DOWN 7
-#define HISI_IRQ_KEY_UP 6
-
-#define HISI_MASK_FIELD 0xFF
-#define HISI_BITS 8
-
-/*define the first group interrupt register number*/
-#define HISI_PMIC_FIRST_GROUP_INT_NUM 2
-
-static const struct mfd_cell hi6421v600_devs[] = {
- { .name = "hi6421v600-regulator", },
-};
-
-static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
-{
- struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)priv;
- unsigned long pending;
- unsigned int data;
- int i, offset;
-
- for (i = 0; i < HISI_IRQ_ARRAY; i++) {
- regmap_read(pmic->map, offset, &data);
- data &= HISI_MASK_FIELD;
- if (data != 0)
- pr_debug("data[%d]=0x%d\n\r", i, data);
- regmap_write(pmic->map, i + SOC_PMIC_IRQ0_ADDR, data);
-
- /* for_each_set_bit() macro requires unsigned long */
- pending = data;
-
- /* 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);
- unsigned long flags;
- unsigned int data;
- u32 offset;
-
- offset = (irqd_to_hwirq(d) >> 3);
- offset += SOC_PMIC_IRQ_MASK_0_ADDR;
-
- spin_lock_irqsave(&pmic->lock, flags);
-
- regmap_read(pmic->map, offset, &data);
- data |= (1 << (irqd_to_hwirq(d) & 0x07));
- regmap_write(pmic->map, offset, data);
- spin_unlock_irqrestore(&pmic->lock, flags);
-}
-
-static void hi6421_spmi_irq_unmask(struct irq_data *d)
-{
- struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
- u32 data, offset;
- unsigned long flags;
-
- offset = (irqd_to_hwirq(d) >> 3);
- offset += SOC_PMIC_IRQ_MASK_0_ADDR;
-
- spin_lock_irqsave(&pmic->lock, flags);
- regmap_read(pmic->map, offset, &data);
- data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
- regmap_write(pmic->map, offset, data);
- spin_unlock_irqrestore(&pmic->lock, flags);
-}
-
-static struct irq_chip hi6421_spmi_pmu_irqchip = {
- .name = "hisi-irq",
- .irq_mask = hi6421_spmi_irq_mask,
- .irq_unmask = hi6421_spmi_irq_unmask,
- .irq_disable = hi6421_spmi_irq_mask,
- .irq_enable = hi6421_spmi_irq_unmask,
-};
-
-static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct hi6421_spmi_pmic *pmic = d->host_data;
-
- irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
- handle_simple_irq, "hisi");
- irq_set_chip_data(virq, pmic);
- irq_set_irq_type(virq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops hi6421_spmi_domain_ops = {
- .map = hi6421_spmi_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
-{
- int i;
- unsigned int pending;
-
- for (i = 0 ; i < HISI_IRQ_ARRAY; i++)
- regmap_write(pmic->map, SOC_PMIC_IRQ_MASK_0_ADDR + i,
- HISI_MASK_STATE);
-
- for (i = 0 ; i < HISI_IRQ_ARRAY; i++) {
- regmap_read(pmic->map, SOC_PMIC_IRQ0_ADDR + i, &pending);
-
- pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
- SOC_PMIC_IRQ0_ADDR + i, pending);
- regmap_write(pmic->map, SOC_PMIC_IRQ0_ADDR + i,
- HISI_MASK_STATE);
- }
-}
-
-static const struct regmap_config spmi_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = 0xffff,
- .fast_io = true
-};
-
-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;
- struct regmap *map;
- unsigned int virq;
- int ret, i;
-
- pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic)
- return -ENOMEM;
-
- map = devm_regmap_init_spmi_ext(pdev, &spmi_regmap_config);
- if (IS_ERR(map))
- return PTR_ERR(map);
-
- spin_lock_init(&pmic->lock);
-
- pmic->dev = dev;
- pmic->map = map;
-
- pmic->gpio = of_get_gpio(np, 0);
- if (pmic->gpio < 0)
- return pmic->gpio;
-
- if (!gpio_is_valid(pmic->gpio))
- return -EINVAL;
-
- ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic");
- if (ret < 0) {
- dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
- return ret;
- }
-
- pmic->irq = gpio_to_irq(pmic->gpio);
-
- hi6421_spmi_pmic_irq_prc(pmic);
-
- pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
- if (!pmic->irqs)
- goto irq_malloc;
-
- pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
- &hi6421_spmi_domain_ops, pmic);
- if (!pmic->domain) {
- dev_err(dev, "failed irq domain add simple!\n");
- ret = -ENODEV;
- goto irq_malloc;
- }
-
- for (i = 0; i < HISI_IRQ_NUM; i++) {
- virq = irq_create_mapping(pmic->domain, i);
- if (!virq) {
- dev_err(dev, "Failed mapping hwirq\n");
- ret = -ENOSPC;
- goto irq_malloc;
- }
- pmic->irqs[i] = virq;
- dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n",
- __func__, i, pmic->irqs[i]);
- }
-
- ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
- IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
- "pmic", pmic);
- if (ret < 0) {
- dev_err(dev, "could not claim pmic IRQ: error %d\n", ret);
- goto irq_malloc;
- }
-
- dev_set_drvdata(&pdev->dev, pmic);
-
- /*
- * The logic below will rely that the pmic is already stored at
- * drvdata.
- */
- dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n",
- pdev->dev.of_node);
- ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
- hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
- NULL, 0, NULL);
- if (!ret)
- return 0;
-
- dev_err(dev, "Failed to add child devices: %d\n", ret);
-
-irq_malloc:
- free_irq(pmic->irq, pmic);
-
- return ret;
-}
-
-static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
-{
- struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
-
- free_irq(pmic->irq, pmic);
-}
-
-static const struct of_device_id pmic_spmi_id_table[] = {
- { .compatible = "hisilicon,hi6421-spmi" },
- { }
-};
-MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
-
-static struct spmi_driver hi6421_spmi_pmic_driver = {
- .driver = {
- .name = "hi6421-spmi-pmic",
- .of_match_table = pmic_spmi_id_table,
- },
- .probe = hi6421_spmi_pmic_probe,
- .remove = hi6421_spmi_pmic_remove,
-};
-module_spmi_driver(hi6421_spmi_pmic_driver);
-
-MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
deleted file mode 100644
index 3b23ad56b31a..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
+++ /dev/null
@@ -1,135 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: HiSilicon 6421v600 SPMI PMIC
-
-maintainers:
- - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-
-description: |
- HiSilicon 6421v600 should be connected inside a MIPI System Power Management
- (SPMI) bus. It provides interrupts and power supply.
-
- The GPIO and interrupt settings are represented as part of the top-level PMIC
- node.
-
- The SPMI controller part is provided by
- drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
-
-properties:
- $nodename:
- pattern: "pmic@[0-9a-f]"
-
- compatible:
- const: hisilicon,hi6421v600-spmi
-
- reg:
- maxItems: 1
-
- '#interrupt-cells':
- const: 2
-
- interrupt-controller:
- description:
- Identify that the PMIC is capable of behaving as an interrupt controller.
-
- gpios:
- maxItems: 1
-
- regulators:
- type: object
-
- properties:
- '#address-cells':
- const: 1
-
- '#size-cells':
- const: 0
-
- patternProperties:
- '^ldo[0-9]+@[0-9a-f]$':
- type: object
-
- $ref: "/schemas/regulator/regulator.yaml#"
-
-required:
- - compatible
- - reg
- - regulators
-
-additionalProperties: false
-
-examples:
- - |
- /* pmic properties */
-
- pmic: pmic@0 {
- compatible = "hisilicon,hi6421-spmi";
- reg = <0 0>;
-
- #interrupt-cells = <2>;
- interrupt-controller;
- gpios = <&gpio28 0 0>;
-
- regulators {
- #address-cells = <1>;
- #size-cells = <0>;
-
- ldo3: LDO3 {
- regulator-name = "ldo3";
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <2000000>;
- regulator-boot-on;
- };
-
- ldo4: LDO4 {
- regulator-name = "ldo4";
- regulator-min-microvolt = <1725000>;
- regulator-max-microvolt = <1900000>;
- regulator-boot-on;
- };
-
- ldo9: LDO9 {
- regulator-name = "ldo9";
- regulator-min-microvolt = <1750000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- ldo15: LDO15 {
- regulator-name = "ldo15";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo16: LDO16 {
- regulator-name = "ldo16";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3000000>;
- regulator-boot-on;
- };
-
- ldo17: LDO17 {
- regulator-name = "ldo17";
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo33: LDO33 {
- regulator-name = "ldo33";
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- ldo34: LDO34 {
- regulator-name = "ldo34";
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <3300000>;
- };
- };
- };
--
2.29.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 18/21] mfd: hi6421-spmi-pmic: move driver from staging
2021-01-19 16:10 ` [PATCH v4 18/21] mfd: hi6421-spmi-pmic: " Mauro Carvalho Chehab
@ 2021-01-27 11:05 ` Lee Jones
2021-02-05 22:26 ` Rob Herring
2021-02-05 22:26 ` Rob Herring
2 siblings, 0 replies; 10+ messages in thread
From: Lee Jones @ 2021-01-27 11:05 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mark Brown, Greg Kroah-Hartman, Mayulong, Rob Herring, devel,
devicetree, linux-kernel
On Tue, 19 Jan 2021, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 135 +++++++++
> MAINTAINERS | 7 +
> drivers/mfd/Kconfig | 15 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/hi6421-spmi-pmic.c | 281 ++++++++++++++++++
> drivers/staging/hikey9xx/Kconfig | 16 -
> drivers/staging/hikey9xx/Makefile | 1 -
> drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 281 ------------------
> .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 135 ---------
> 9 files changed, 439 insertions(+), 433 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
>
> diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> new file mode 100644
> index 000000000000..3b23ad56b31a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> @@ -0,0 +1,135 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HiSilicon 6421v600 SPMI PMIC
> +
> +maintainers:
> + - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +
> +description: |
> + HiSilicon 6421v600 should be connected inside a MIPI System Power Management
> + (SPMI) bus. It provides interrupts and power supply.
> +
> + The GPIO and interrupt settings are represented as part of the top-level PMIC
> + node.
> +
> + The SPMI controller part is provided by
> + drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
> +
> +properties:
> + $nodename:
> + pattern: "pmic@[0-9a-f]"
> +
> + compatible:
> + const: hisilicon,hi6421v600-spmi
> +
> + reg:
> + maxItems: 1
> +
> + '#interrupt-cells':
> + const: 2
> +
> + interrupt-controller:
> + description:
> + Identify that the PMIC is capable of behaving as an interrupt controller.
> +
> + gpios:
> + maxItems: 1
> +
> + regulators:
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + '^ldo[0-9]+@[0-9a-f]$':
> + type: object
> +
> + $ref: "/schemas/regulator/regulator.yaml#"
> +
> +required:
> + - compatible
> + - reg
> + - regulators
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + /* pmic properties */
> +
> + pmic: pmic@0 {
> + compatible = "hisilicon,hi6421-spmi";
> + reg = <0 0>;
> +
> + #interrupt-cells = <2>;
> + interrupt-controller;
> + gpios = <&gpio28 0 0>;
> +
> + regulators {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ldo3: LDO3 {
> + regulator-name = "ldo3";
> + regulator-min-microvolt = <1500000>;
> + regulator-max-microvolt = <2000000>;
> + regulator-boot-on;
> + };
> +
> + ldo4: LDO4 {
> + regulator-name = "ldo4";
> + regulator-min-microvolt = <1725000>;
> + regulator-max-microvolt = <1900000>;
> + regulator-boot-on;
> + };
> +
> + ldo9: LDO9 {
> + regulator-name = "ldo9";
> + regulator-min-microvolt = <1750000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-boot-on;
> + };
> +
> + ldo15: LDO15 {
> + regulator-name = "ldo15";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <3000000>;
> + regulator-always-on;
> + };
> +
> + ldo16: LDO16 {
> + regulator-name = "ldo16";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <3000000>;
> + regulator-boot-on;
> + };
> +
> + ldo17: LDO17 {
> + regulator-name = "ldo17";
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <3300000>;
> + };
> +
> + ldo33: LDO33 {
> + regulator-name = "ldo33";
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-boot-on;
> + };
> +
> + ldo34: LDO34 {
> + regulator-name = "ldo34";
> + regulator-min-microvolt = <2600000>;
> + regulator-max-microvolt = <3300000>;
> + };
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 85e5b6ab57ca..c5b36a58ede5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8006,6 +8006,13 @@ S: Maintained
> F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
> F: drivers/spmi/hisi-spmi-controller.c
>
> +HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
> +M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +L: linux-kernel@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> +F: drivers/mfd/hi6421-spmi-pmic.c
> +
> HISILICON STAGING DRIVERS FOR HIKEY 960/970
> M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> L: devel@driverdev.osuosl.org
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 8b99a13669bf..c04c2f6be1d9 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -509,6 +509,21 @@ config MFD_HI6421_PMIC
> menus in order to enable them.
> We communicate with the Hi6421 via memory-mapped I/O.
>
> +config MFD_HI6421_SPMI
> + tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
> + depends on OF
> + depends on SPMI
> + select MFD_CORE
> + help
> + Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
> + multi-functions, such as regulators, RTC, codec, Coulomb counter,
> + etc.
> +
> + This driver includes core APIs _only_. You have to select
> + individual components like voltage regulators under corresponding
> + menus in order to enable them.
> + We communicate with the Hi6421v600 via a SPMI bus.
> +
> config MFD_HI655X_PMIC
> tristate "HiSilicon Hi655X series PMU/Codec IC"
> depends on ARCH_HISI || COMPILE_TEST
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 1780019d2474..7744993c42bc 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -233,6 +233,7 @@ obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
> obj-$(CONFIG_MFD_IQS62X) += iqs62x.o
> obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
> obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
> +obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
> obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
> obj-$(CONFIG_MFD_DLN2) += dln2.o
> obj-$(CONFIG_MFD_RT5033) += rt5033.o
> diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
> new file mode 100644
> index 000000000000..99c4f3359f71
> --- /dev/null
> +++ b/drivers/mfd/hi6421-spmi-pmic.c
> @@ -0,0 +1,281 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Device driver for regulators in HISI PMIC IC
> +//
> +// Copyright (c) 2013 Linaro Ltd.
> +// Copyright (c) 2011 Hisilicon.
> +//
No need for this blank line.
> +// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
Only the SPDX line as C++ comments please.
'\n' here.
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/hi6421-spmi-pmic.h>
> +#include <linux/module.h>
> +#include <linux/of_gpio.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/spmi.h>
> +
> +/* 8-bit register offset in PMIC */
> +#define HISI_MASK_STATE 0xff
> +
> +#define HISI_IRQ_ARRAY 2
> +#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8)
> +
> +#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
> +#define SOC_PMIC_IRQ0_ADDR 0x0212
> +
> +#define HISI_IRQ_KEY_NUM 0
> +#define HISI_IRQ_KEY_VALUE 0xc0
> +#define HISI_IRQ_KEY_DOWN 7
> +#define HISI_IRQ_KEY_UP 6
> +
> +#define HISI_MASK_FIELD 0xFF
> +#define HISI_BITS 8
> +
> +/*define the first group interrupt register number*/
I think the nomenclature is forthcoming enough for this to be omitted.
It's also in the wrong format.
> +#define HISI_PMIC_FIRST_GROUP_INT_NUM 2
> +
> +static const struct mfd_cell hi6421v600_devs[] = {
> + { .name = "hi6421v600-regulator", },
> +};
Where are the reset of the devices?
> +static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
> +{
> + struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)priv;
> + unsigned long pending;
> + unsigned int data;
> + int i, offset;
> +
> + for (i = 0; i < HISI_IRQ_ARRAY; i++) {
> + regmap_read(pmic->map, offset, &data);
"map" is ambiguous. Please rename this to 'regamp'.
What exactly is this reading?
Offset looks decidedly unassigned to me.
> + data &= HISI_MASK_FIELD;
> + if (data != 0)
> + pr_debug("data[%d]=0x%d\n\r", i, data);
How useful is this, really?
> + regmap_write(pmic->map, i + SOC_PMIC_IRQ0_ADDR, data);
Nit: I can't help feeling this would read better as the address plus
the offset.
> + /* for_each_set_bit() macro requires unsigned long */
Not sure this requires a comment?
> + pending = data;
Would a cast work better?
> + /* solve powerkey order */
What does this mean? Please elaborate.
Please use English grammar in comments i.e. begin with a capital letter.
> + if ((i == HISI_IRQ_KEY_NUM) &&
> + ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) {
Excessive bracketing used here.
> + 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);
> + unsigned long flags;
> + unsigned int data;
> + u32 offset;
> +
> + offset = (irqd_to_hwirq(d) >> 3);
Why 3? Probably better to define these shifts/masks rather than use
magic numbers with no comments.
> + offset += SOC_PMIC_IRQ_MASK_0_ADDR;
> +
> + spin_lock_irqsave(&pmic->lock, flags);
> +
Keep these symmetrical for ease of reading.
Either add a '\n' before the unlock or remove this one.
> + regmap_read(pmic->map, offset, &data);
> + data |= (1 << (irqd_to_hwirq(d) & 0x07));
What are you doing here?
Maybe improved defines will be enough. If not, please supply a
suitable comment.
> + regmap_write(pmic->map, offset, data);
> + spin_unlock_irqrestore(&pmic->lock, flags);
> +}
> +
> +static void hi6421_spmi_irq_unmask(struct irq_data *d)
> +{
> + struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d);
> + u32 data, offset;
> + unsigned long flags;
> +
> + offset = (irqd_to_hwirq(d) >> 3);
> + offset += SOC_PMIC_IRQ_MASK_0_ADDR;
> +
> + spin_lock_irqsave(&pmic->lock, flags);
> + regmap_read(pmic->map, offset, &data);
> + data &= ~(1 << (irqd_to_hwirq(d) & 0x07));
> + regmap_write(pmic->map, offset, data);
> + spin_unlock_irqrestore(&pmic->lock, flags);
> +}
> +
> +static struct irq_chip hi6421_spmi_pmu_irqchip = {
> + .name = "hisi-irq",
> + .irq_mask = hi6421_spmi_irq_mask,
> + .irq_unmask = hi6421_spmi_irq_unmask,
> + .irq_disable = hi6421_spmi_irq_mask,
> + .irq_enable = hi6421_spmi_irq_unmask,
> +};
> +
> +static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
> + irq_hw_number_t hw)
> +{
> + struct hi6421_spmi_pmic *pmic = d->host_data;
> +
> + irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
> + handle_simple_irq, "hisi");
> + irq_set_chip_data(virq, pmic);
> + irq_set_irq_type(virq, IRQ_TYPE_NONE);
> +
> + return 0;
> +}
> +
> +static const struct irq_domain_ops hi6421_spmi_domain_ops = {
> + .map = hi6421_spmi_irq_map,
> + .xlate = irq_domain_xlate_twocell,
> +};
> +
> +static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic)
> +{
> + int i;
> + unsigned int pending;
> +
> + for (i = 0 ; i < HISI_IRQ_ARRAY; i++)
Misplaced ' '.
> + regmap_write(pmic->map, SOC_PMIC_IRQ_MASK_0_ADDR + i,
> + HISI_MASK_STATE);
> +
> + for (i = 0 ; i < HISI_IRQ_ARRAY; i++) {
> + regmap_read(pmic->map, SOC_PMIC_IRQ0_ADDR + i, &pending);
> +
> + pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n",
> + SOC_PMIC_IRQ0_ADDR + i, pending);
Again, is this actually useful to anyone now that the driver is nearly
10 years old. Particularly anyone who can't add a quick printk()
during a debug session?
> + regmap_write(pmic->map, SOC_PMIC_IRQ0_ADDR + i,
> + HISI_MASK_STATE);
> + }
> +}
> +
> +static const struct regmap_config spmi_regmap_config = {
> + .reg_bits = 16,
> + .val_bits = 8,
> + .max_register = 0xffff,
> + .fast_io = true
> +};
> +
> +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;
> + struct regmap *map;
> + unsigned int virq;
> + int ret, i;
> +
> + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
Nit: My personal preference for local driver data is 'ddata'.
> + if (!pmic)
> + return -ENOMEM;
> +
> + map = devm_regmap_init_spmi_ext(pdev, &spmi_regmap_config);
We talk about IRQ maps above. 'regmap' would be better here.
> + if (IS_ERR(map))
> + return PTR_ERR(map);
> +
> + spin_lock_init(&pmic->lock);
> +
> + pmic->dev = dev;
> + pmic->map = map;
> +
> + pmic->gpio = of_get_gpio(np, 0);
Why do you use local variable 'map' above and just assign the ddata
value directly here? I think the latter would be better throughout.
> + if (pmic->gpio < 0)
> + return pmic->gpio;
> +
> + if (!gpio_is_valid(pmic->gpio))
> + return -EINVAL;
> +
> + ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic");
> + if (ret < 0) {
> + dev_err(dev, "failed to request gpio%d\n", pmic->gpio);
> + return ret;
> + }
> +
> + pmic->irq = gpio_to_irq(pmic->gpio);
> +
> + hi6421_spmi_pmic_irq_prc(pmic);
What does prc mean?
> + pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL);
> + if (!pmic->irqs)
> + goto irq_malloc;
malloc?
> + pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0,
> + &hi6421_spmi_domain_ops, pmic);
> + if (!pmic->domain) {
> + dev_err(dev, "failed irq domain add simple!\n");
Too specific in my opinion. No need to mention the call.
"Failed to create IRQ domain" would be better IMHO.
> + ret = -ENODEV;
> + goto irq_malloc;
> + }
> +
> + for (i = 0; i < HISI_IRQ_NUM; i++) {
> + virq = irq_create_mapping(pmic->domain, i);
> + if (!virq) {
> + dev_err(dev, "Failed mapping hwirq\n");
"Failed to map H/W IRQ"
> + ret = -ENOSPC;
> + goto irq_malloc;
> + }
> + pmic->irqs[i] = virq;
> + dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n",
> + __func__, i, pmic->irqs[i]);
This is ugly. Please remove it.
> + }
> +
> + ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL,
> + IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
> + "pmic", pmic);
> + if (ret < 0) {
> + dev_err(dev, "could not claim pmic IRQ: error %d\n", ret);
This is inconsistent with other prints. Better to start with a
capital I think. Also, it should be "PMIC", as it's an abbreviation.
> + goto irq_malloc;
> + }
> +
> + dev_set_drvdata(&pdev->dev, pmic);
> +
> + /*
> + * The logic below will rely that the pmic is already stored at
> + * drvdata.
> + */
Which logic?
> + dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n",
> + pdev->dev.of_node);
Please remove this.
> + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> + hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
> + NULL, 0, NULL);
> + if (!ret)
> + return 0;
> +
> + dev_err(dev, "Failed to add child devices: %d\n", ret);
> +
> +irq_malloc:
> + free_irq(pmic->irq, pmic);
Does gpio_to_irq() need freeing?
> + return ret;
> +}
> +
> +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> +{
> + struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev);
> +
> + free_irq(pmic->irq, pmic);
> +}
> +
> +static const struct of_device_id pmic_spmi_id_table[] = {
> + { .compatible = "hisilicon,hi6421-spmi" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
> +
> +static struct spmi_driver hi6421_spmi_pmic_driver = {
> + .driver = {
> + .name = "hi6421-spmi-pmic",
Odd spacing. Just use one ' ' please.
> + .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");
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 18/21] mfd: hi6421-spmi-pmic: move driver from staging
2021-01-19 16:10 ` [PATCH v4 18/21] mfd: hi6421-spmi-pmic: " Mauro Carvalho Chehab
2021-01-27 11:05 ` Lee Jones
@ 2021-02-05 22:26 ` Rob Herring
2021-02-05 22:26 ` Rob Herring
2 siblings, 0 replies; 10+ messages in thread
From: Rob Herring @ 2021-02-05 22:26 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mark Brown, Lee Jones, Greg Kroah-Hartman, Mayulong, devel,
devicetree, linux-kernel
On Tue, Jan 19, 2021 at 05:10:44PM +0100, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 135 +++++++++
> MAINTAINERS | 7 +
> drivers/mfd/Kconfig | 15 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/hi6421-spmi-pmic.c | 281 ++++++++++++++++++
> drivers/staging/hikey9xx/Kconfig | 16 -
> drivers/staging/hikey9xx/Makefile | 1 -
> drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 281 ------------------
> .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 135 ---------
> 9 files changed, 439 insertions(+), 433 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
>
> diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> new file mode 100644
> index 000000000000..3b23ad56b31a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> @@ -0,0 +1,135 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HiSilicon 6421v600 SPMI PMIC
> +
> +maintainers:
> + - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +
> +description: |
> + HiSilicon 6421v600 should be connected inside a MIPI System Power Management
> + (SPMI) bus. It provides interrupts and power supply.
> +
> + The GPIO and interrupt settings are represented as part of the top-level PMIC
> + node.
> +
> + The SPMI controller part is provided by
> + drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
> +
> +properties:
> + $nodename:
> + pattern: "pmic@[0-9a-f]"
> +
> + compatible:
> + const: hisilicon,hi6421v600-spmi
'-spmi' is redundant.
> +
> + reg:
> + maxItems: 1
> +
> + '#interrupt-cells':
> + const: 2
> +
> + interrupt-controller:
> + description:
> + Identify that the PMIC is capable of behaving as an interrupt controller.
Don't need a description here.
Don't you need 'interrupts' here to get the interrupts to the host?
> +
> + gpios:
> + maxItems: 1
GPIO for what? It's preferred to have a named gpio.
> +
> + regulators:
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + '^ldo[0-9]+@[0-9a-f]$':
> + type: object
> +
> + $ref: "/schemas/regulator/regulator.yaml#"
additionalProperties: false
Which will give you errors in the example.
> +
> +required:
> + - compatible
> + - reg
> + - regulators
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + /* pmic properties */
> +
> + pmic: pmic@0 {
> + compatible = "hisilicon,hi6421-spmi";
> + reg = <0 0>;
> +
> + #interrupt-cells = <2>;
> + interrupt-controller;
> + gpios = <&gpio28 0 0>;
> +
> + regulators {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ldo3: LDO3 {
LDO3: ldo3 {
is preferred and closer to what you defined above.
> + regulator-name = "ldo3";
> + regulator-min-microvolt = <1500000>;
> + regulator-max-microvolt = <2000000>;
> + regulator-boot-on;
> + };
> +
> + ldo4: LDO4 {
> + regulator-name = "ldo4";
> + regulator-min-microvolt = <1725000>;
> + regulator-max-microvolt = <1900000>;
> + regulator-boot-on;
> + };
> +
> + ldo9: LDO9 {
> + regulator-name = "ldo9";
> + regulator-min-microvolt = <1750000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-boot-on;
> + };
> +
> + ldo15: LDO15 {
> + regulator-name = "ldo15";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <3000000>;
> + regulator-always-on;
> + };
> +
> + ldo16: LDO16 {
> + regulator-name = "ldo16";
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <3000000>;
> + regulator-boot-on;
> + };
> +
> + ldo17: LDO17 {
> + regulator-name = "ldo17";
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <3300000>;
> + };
> +
> + ldo33: LDO33 {
> + regulator-name = "ldo33";
> + regulator-min-microvolt = <2500000>;
> + regulator-max-microvolt = <3300000>;
> + regulator-boot-on;
> + };
> +
> + ldo34: LDO34 {
> + regulator-name = "ldo34";
> + regulator-min-microvolt = <2600000>;
> + regulator-max-microvolt = <3300000>;
> + };
> + };
> + };
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 18/21] mfd: hi6421-spmi-pmic: move driver from staging
2021-01-19 16:10 ` [PATCH v4 18/21] mfd: hi6421-spmi-pmic: " Mauro Carvalho Chehab
2021-01-27 11:05 ` Lee Jones
2021-02-05 22:26 ` Rob Herring
@ 2021-02-05 22:26 ` Rob Herring
2 siblings, 0 replies; 10+ messages in thread
From: Rob Herring @ 2021-02-05 22:26 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mark Brown, Lee Jones, Greg Kroah-Hartman, Mayulong, devel,
devicetree, linux-kernel
On Tue, Jan 19, 2021 at 05:10:44PM +0100, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> ---
> .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 135 +++++++++
> MAINTAINERS | 7 +
> drivers/mfd/Kconfig | 15 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/hi6421-spmi-pmic.c | 281 ++++++++++++++++++
> drivers/staging/hikey9xx/Kconfig | 16 -
> drivers/staging/hikey9xx/Makefile | 1 -
> drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 281 ------------------
> .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 135 ---------
> 9 files changed, 439 insertions(+), 433 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> create mode 100644 drivers/mfd/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
>
> diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> new file mode 100644
> index 000000000000..3b23ad56b31a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> @@ -0,0 +1,135 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HiSilicon 6421v600 SPMI PMIC
> +
> +maintainers:
> + - Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> +
> +description: |
> + HiSilicon 6421v600 should be connected inside a MIPI System Power Management
> + (SPMI) bus. It provides interrupts and power supply.
> +
> + The GPIO and interrupt settings are represented as part of the top-level PMIC
> + node.
> +
> + The SPMI controller part is provided by
> + drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
> +
> +properties:
> + $nodename:
> + pattern: "pmic@[0-9a-f]"
> +
> + compatible:
> + const: hisilicon,hi6421v600-spmi
Also, use the compatible string as the filename.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 20/21] dts: hisilicon: add support for USB3 on Hikey 970
2021-01-19 16:10 [PATCH v4 00/21] Move Hisilicon 6421v600 SPMI driver set out of staging Mauro Carvalho Chehab
2021-01-19 16:10 ` [PATCH v4 17/21] spmi: hisi-spmi-controller: move driver from staging Mauro Carvalho Chehab
2021-01-19 16:10 ` [PATCH v4 18/21] mfd: hi6421-spmi-pmic: " Mauro Carvalho Chehab
@ 2021-01-19 16:10 ` Mauro Carvalho Chehab
2021-01-19 16:10 ` [PATCH v4 21/21] dts: hisilicon: add support for the PMIC found " Mauro Carvalho Chehab
3 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2021-01-19 16:10 UTC (permalink / raw)
To: Mark Brown, Lee Jones
Cc: Mauro Carvalho Chehab, Rob Herring, Wei Xu, devicetree,
linux-arm-kernel, linux-kernel
Add the USB3 bindings for Kirin 970 phy and Hikey 970 board.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.../boot/dts/hisilicon/hi3670-hikey970.dts | 102 ++++++++++++++++++
arch/arm64/boot/dts/hisilicon/hi3670.dtsi | 58 ++++++++++
2 files changed, 160 insertions(+)
diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
index 7f9f9886c349..fe6600dbad61 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
@@ -69,6 +69,29 @@ wlan_en: wlan-en-1-8v {
startup-delay-us = <70000>;
enable-active-high;
};
+ hikey_usbhub: hikey_usbhub {
+ compatible = "hisilicon,kirin970_hikey_usbhub";
+
+ typec-vbus-gpios = <&gpio26 1 0>;
+ otg-switch-gpios = <&gpio4 2 0>;
+ hub_reset_en_gpio = <&gpio0 3 0>;
+ hub-vdd-supply = <&ldo17>;
+ usb-role-switch;
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hikey_usb_ep0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&dwc3_role_switch>;
+ };
+ hikey_usb_ep1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&rt1711h_ep>;
+ };
+ };
+ };
};
/*
@@ -446,3 +469,82 @@ &uart6 {
label = "LS-UART1";
status = "okay";
};
+
+&i2c1 {
+ status = "okay";
+
+ rt1711h: rt1711h@4e {
+ compatible = "richtek,rt1711h";
+ reg = <0x4e>;
+ status = "okay";
+ interrupt-parent = <&gpio27>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_cfg_func>;
+
+ usb_con: connector {
+ compatible = "usb-c-connector";
+ label = "USB-C";
+ data-role = "dual";
+ power-role = "dual";
+ try-power-role = "sink";
+ source-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)>;
+ sink-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)
+ PDO_VAR(5000, 5000, 1000)>;
+ op-sink-microwatt = <10000000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@1 {
+ reg = <1>;
+ usb_con_ss: endpoint {
+ remote-endpoint = <&dwc3_ss>;
+ };
+ };
+ };
+ };
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rt1711h_ep: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&hikey_usb_ep1>;
+ };
+ };
+ };
+};
+
+&i2c2 {
+ /* USB HUB is on this bus at address 0x44 */
+ status = "okay";
+};
+
+&dwc3 { /* USB */
+ dr_mode = "otg";
+ maximum-speed = "super-speed";
+ phy_type = "utmi";
+ snps,dis-del-phy-power-chg-quirk;
+ snps,dis_u2_susphy_quirk;
+ snps,dis_u3_susphy_quirk;
+ snps,tx_de_emphasis_quirk;
+ snps,tx_de_emphasis = <1>;
+ snps,dis-split-quirk;
+ snps,gctl-reset-quirk;
+ usb-role-switch;
+ role-switch-default-mode = "host";
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dwc3_role_switch: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&hikey_usb_ep0>;
+ };
+
+ dwc3_ss: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&usb_con_ss>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
index 36d3ae493c7d..d44af856f90d 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi3670.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/hi3670-clock.h>
+#include <dt-bindings/usb/pd.h>
/ {
compatible = "hisilicon,hi3670";
@@ -786,5 +787,62 @@ i2c4: i2c@fdf0d000 {
pinctrl-0 = <&i2c4_pmx_func &i2c4_cfg_func>;
status = "disabled";
};
+
+ usb3_otg_bc: usb3_otg_bc@ff200000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x0 0xff200000 0x0 0x1000>;
+
+ usb_phy: usbphy {
+ compatible = "hisilicon,hi3670-usb-phy";
+ #phy-cells = <0>;
+ hisilicon,pericrg-syscon = <&crg_ctrl>;
+ hisilicon,pctrl-syscon = <&pctrl>;
+ hisilicon,sctrl-syscon = <&sctrl>;
+ hisilicon,eye-diagram-param = <0xFDFEE4>;
+ hisilicon,tx-vboost-lvl = <0x5>;
+
+ phy-supply = <&ldo17>;
+ };
+ };
+
+ usb31_misc_rst: usb31_misc_rst_controller {
+ compatible = "hisilicon,hi3660-reset";
+ #reset-cells = <2>;
+ hisi,rst-syscon = <&usb3_otg_bc>;
+ };
+
+ usb3: hisi_dwc3 {
+ compatible = "hisilicon,hi3670-dwc3";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ clocks = <&crg_ctrl HI3670_CLK_GATE_ABB_USB>,
+ <&crg_ctrl HI3670_HCLK_GATE_USB3OTG>,
+ <&crg_ctrl HI3670_CLK_GATE_USB3OTG_REF>,
+ <&crg_ctrl HI3670_ACLK_GATE_USB3DVFS>;
+ clock-names = "clk_gate_abb_usb",
+ "hclk_gate_usb3otg",
+ "clk_gate_usb3otg_ref",
+ "aclk_gate_usb3dvfs";
+
+ assigned-clocks = <&crg_ctrl HI3670_ACLK_GATE_USB3DVFS>;
+ assigned-clock-rates = <238000000>;
+ resets = <&crg_rst 0x90 6>,
+ <&crg_rst 0x90 7>,
+ <&usb31_misc_rst 0xA0 8>,
+ <&usb31_misc_rst 0xA0 9>;
+
+ dwc3: dwc3@ff100000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0xff100000 0x0 0x100000>;
+
+ interrupts = <0 159 IRQ_TYPE_LEVEL_HIGH>,
+ <0 161 IRQ_TYPE_LEVEL_HIGH>;
+
+ phys = <&usb_phy>;
+ phy-names = "usb3-phy";
+ };
+ };
};
};
--
2.29.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 21/21] dts: hisilicon: add support for the PMIC found on Hikey 970
2021-01-19 16:10 [PATCH v4 00/21] Move Hisilicon 6421v600 SPMI driver set out of staging Mauro Carvalho Chehab
` (2 preceding siblings ...)
2021-01-19 16:10 ` [PATCH v4 20/21] dts: hisilicon: add support for USB3 on Hikey 970 Mauro Carvalho Chehab
@ 2021-01-19 16:10 ` Mauro Carvalho Chehab
3 siblings, 0 replies; 10+ messages in thread
From: Mauro Carvalho Chehab @ 2021-01-19 16:10 UTC (permalink / raw)
To: Mark Brown, Lee Jones
Cc: Mauro Carvalho Chehab, Rob Herring, Wei Xu, devicetree,
linux-arm-kernel, linux-kernel
Add a device tree for the HiSilicon 6421v600 SPMI PMIC, used
on HiKey970 board.
As we now have support for it, change the fixed regulators
used by the SD I/O to use the proper LDO supplies.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
.../boot/dts/hisilicon/hi3670-hikey970.dts | 22 +----
.../boot/dts/hisilicon/hikey970-pmic.dtsi | 87 +++++++++++++++++++
2 files changed, 90 insertions(+), 19 deletions(-)
create mode 100644 arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
diff --git a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
index fe6600dbad61..1f221cb97690 100644
--- a/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
@@ -12,6 +12,7 @@
#include "hi3670.dtsi"
#include "hikey970-pinctrl.dtsi"
+#include "hikey970-pmic.dtsi"
/ {
model = "HiKey970";
@@ -39,23 +40,6 @@ memory@0 {
reg = <0x0 0x0 0x0 0x0>;
};
- sd_1v8: regulator-1v8 {
- compatible = "regulator-fixed";
- regulator-name = "fixed-1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- sd_3v3: regulator-3v3 {
- compatible = "regulator-fixed";
- regulator-name = "fixed-3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- regulator-always-on;
- };
-
wlan_en: wlan-en-1-8v {
compatible = "regulator-fixed";
regulator-name = "wlan-en-regulator";
@@ -425,8 +409,8 @@ &dwmmc1 {
pinctrl-0 = <&sd_pmx_func
&sd_clk_cfg_func
&sd_cfg_func>;
- vmmc-supply = <&sd_3v3>;
- vqmmc-supply = <&sd_1v8>;
+ vmmc-supply = <&ldo16>;
+ vqmmc-supply = <&ldo9>;
status = "okay";
};
diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
new file mode 100644
index 000000000000..8cf45b962fea
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dts file for Hi6421v600 SPMI PMIC used at the HiKey970 Development Board
+ *
+ * Copyright (C) 2020, Huawei Tech. Co., Ltd.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+ spmi: spmi@fff24000 {
+ compatible = "hisilicon,kirin970-spmi-controller";
+ #address-cells = <2>;
+ #size-cells = <0>;
+ status = "okay";
+ reg = <0x0 0xfff24000 0x0 0x1000>;
+ spmi-channel = <2>;
+
+ pmic: pmic@0 {
+ compatible = "hisilicon,hi6421-spmi";
+ reg = <0 SPMI_USID>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ gpios = <&gpio28 0 0>;
+
+ regulators {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ldo3: LDO3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-boot-on;
+ };
+
+ ldo4: LDO4 { /* 40 PIN */
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1725000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-boot-on;
+ };
+
+ ldo9: LDO9 { /* SDCARD I/O */
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo15: LDO15 { /* UFS */
+ regulator-name = "ldo15";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo16: LDO16 { /* SD */
+ regulator-name = "ldo16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ };
+
+ ldo17: LDO17 {
+ regulator-name = "ldo17";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo33: LDO33 { /* PEX8606 */
+ regulator-name = "ldo33";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo34: LDO34 { /* GPS AUX IN VDD */
+ regulator-name = "ldo34";
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+ };
+ };
+};
--
2.29.2
^ permalink raw reply related [flat|nested] 10+ messages in thread