]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
spmi: hisi-spmi-controller: move driver from staging
authorMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Fri, 25 Jun 2021 07:45:54 +0000 (09:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Jun 2021 08:02:05 +0000 (10:02 +0200)
The Hisilicon 6421v600 SPMI driver is ready for mainstream.

So, move it from staging.

Acked-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Link: https://lore.kernel.org/r/35b9f9169889c1f4d51eff8bf2035450c9e02576.1624606660.git.mchehab+huawei@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml [new file with mode: 0644]
MAINTAINERS
drivers/spmi/Kconfig
drivers/spmi/Makefile
drivers/spmi/hisi-spmi-controller.c [new file with mode: 0644]
drivers/staging/hikey9xx/Kconfig
drivers/staging/hikey9xx/Makefile
drivers/staging/hikey9xx/hisi-spmi-controller.c [deleted file]
drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml [deleted file]

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 (file)
index 0000000..f882903
--- /dev/null
@@ -0,0 +1,73 @@
+# 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
+  ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
+
+allOf:
+  - $ref: spmi.yaml#
+
+properties:
+
+  $nodename:
+    pattern: "spmi@[0-9a-f]"
+
+  compatible:
+    const: hisilicon,kirin970-spmi-controller
+
+  reg:
+    maxItems: 1
+
+  hisilicon,spmi-channel:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      number of the Kirin 970 SPMI channel where the SPMI devices are connected.
+
+required:
+  - compatible
+  - reg
+  - hisilicon,spmi-channel
+
+patternProperties:
+  "@[0-9a-f]$":
+    type: object
+
+    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.
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    bus {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      spmi: spmi@fff24000 {
+        compatible = "hisilicon,kirin970-spmi-controller";
+        #address-cells = <2>;
+        #size-cells = <0>;
+        reg = <0x0 0xfff24000 0x0 0x1000>;
+        hisilicon,spmi-channel = <2>;
+
+        pmic@0 {
+          reg = <0 0>;
+          /* pmic properties */
+        };
+      };
+    };
index c5730484254c68c681fbe8d0ed69ecf4b618d0de..13339228f065b75652fde61d6cdb2502151789d9 100644 (file)
@@ -8282,6 +8282,13 @@ S:       Maintained
 W:     http://www.hisilicon.com
 F:     drivers/spi/spi-hisi-kunpeng.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>
 S:     Maintained
index a53bad541f1a34686cb5b14a60708923db823de1..2874b6c26028b45136bd3dc2b2c3ebff95ae94ea 100644 (file)
@@ -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
index 55a94cadeffe4b0a955b48ef7219f53db3f8e959..6e092e6f290c0c71b1851551440214e63a037c48 100644 (file)
@@ -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 (file)
index 0000000..5bd2326
--- /dev/null
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+/*
+ * SPMI register addr
+ */
+#define SPMI_CHANNEL_OFFSET                            0x0300
+#define SPMI_SLAVE_OFFSET                              0x20
+
+#define SPMI_APB_SPMI_CMD_BASE_ADDR                    0x0100
+
+#define SPMI_APB_SPMI_WDATA0_BASE_ADDR                 0x0104
+#define SPMI_APB_SPMI_WDATA1_BASE_ADDR                 0x0108
+#define SPMI_APB_SPMI_WDATA2_BASE_ADDR                 0x010c
+#define SPMI_APB_SPMI_WDATA3_BASE_ADDR                 0x0110
+
+#define SPMI_APB_SPMI_STATUS_BASE_ADDR                 0x0200
+
+#define SPMI_APB_SPMI_RDATA0_BASE_ADDR                 0x0204
+#define SPMI_APB_SPMI_RDATA1_BASE_ADDR                 0x0208
+#define SPMI_APB_SPMI_RDATA2_BASE_ADDR                 0x020c
+#define SPMI_APB_SPMI_RDATA3_BASE_ADDR                 0x0210
+
+#define SPMI_PER_DATAREG_BYTE                          4
+/*
+ * SPMI cmd register
+ */
+#define SPMI_APB_SPMI_CMD_EN                           BIT(31)
+#define SPMI_APB_SPMI_CMD_TYPE_OFFSET                  24
+#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET                        20
+#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET               16
+#define SPMI_APB_SPMI_CMD_ADDR_OFFSET                  0
+
+/* Command Opcodes */
+
+enum spmi_controller_cmd_op_code {
+       SPMI_CMD_REG_ZERO_WRITE = 0,
+       SPMI_CMD_REG_WRITE = 1,
+       SPMI_CMD_REG_READ = 2,
+       SPMI_CMD_EXT_REG_WRITE = 3,
+       SPMI_CMD_EXT_REG_READ = 4,
+       SPMI_CMD_EXT_REG_WRITE_L = 5,
+       SPMI_CMD_EXT_REG_READ_L = 6,
+       SPMI_CMD_REG_RESET = 7,
+       SPMI_CMD_REG_SLEEP = 8,
+       SPMI_CMD_REG_SHUTDOWN = 9,
+       SPMI_CMD_REG_WAKEUP = 10,
+};
+
+/*
+ * SPMI status register
+ */
+#define SPMI_APB_TRANS_DONE                    BIT(0)
+#define SPMI_APB_TRANS_FAIL                    BIT(2)
+
+/* Command register fields */
+#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT     16
+
+/* Maximum number of support PMIC peripherals */
+#define SPMI_CONTROLLER_TIMEOUT_US             1000
+#define SPMI_CONTROLLER_MAX_TRANS_BYTES                16
+
+struct spmi_controller_dev {
+       struct spmi_controller  *controller;
+       struct device           *dev;
+       void __iomem            *base;
+       spinlock_t              lock;
+       u32                     channel;
+};
+
+static int spmi_controller_wait_for_done(struct device *dev,
+                                        struct spmi_controller_dev *ctrl_dev,
+                                        void __iomem *base, u8 sid, u16 addr)
+{
+       u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
+       u32 status, offset;
+
+       offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
+       offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
+
+       do {
+               status = readl(base + offset);
+
+               if (status & SPMI_APB_TRANS_DONE) {
+                       if (status & SPMI_APB_TRANS_FAIL) {
+                               dev_err(dev, "%s: transaction failed (0x%x)\n",
+                                       __func__, status);
+                               return -EIO;
+                       }
+                       dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
+                       return 0;
+               }
+               udelay(1);
+       } while (timeout--);
+
+       dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
+       return -ETIMEDOUT;
+}
+
+static int spmi_read_cmd(struct spmi_controller *ctrl,
+                        u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
+{
+       struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+       u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+       unsigned long flags;
+       u8 *buf = __buf;
+       u32 cmd, data;
+       int rc;
+       u8 op_code, i;
+
+       if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+               dev_err(&ctrl->dev,
+                       "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+                       SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+               return  -EINVAL;
+       }
+
+       switch (opc) {
+       case SPMI_CMD_READ:
+               op_code = SPMI_CMD_REG_READ;
+               break;
+       case SPMI_CMD_EXT_READ:
+               op_code = SPMI_CMD_EXT_REG_READ;
+               break;
+       case SPMI_CMD_EXT_READL:
+               op_code = SPMI_CMD_EXT_REG_READ_L;
+               break;
+       default:
+               dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
+               return -EINVAL;
+       }
+
+       cmd = SPMI_APB_SPMI_CMD_EN |
+            (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+            ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+            ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
+            ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
+
+       spin_lock_irqsave(&spmi_controller->lock, flags);
+
+       writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
+
+       rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
+                                          spmi_controller->base, slave_id, slave_addr);
+       if (rc)
+               goto done;
+
+       for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+               data = readl(spmi_controller->base + chnl_ofst +
+                            SPMI_SLAVE_OFFSET * slave_id +
+                            SPMI_APB_SPMI_RDATA0_BASE_ADDR +
+                            i * SPMI_PER_DATAREG_BYTE);
+               data = be32_to_cpu((__be32 __force)data);
+               if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+                       memcpy(buf, &data, sizeof(data));
+                       buf += sizeof(data);
+               } else {
+                       memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
+                       buf += (bc % SPMI_PER_DATAREG_BYTE);
+               }
+       }
+
+done:
+       spin_unlock_irqrestore(&spmi_controller->lock, flags);
+       if (rc)
+               dev_err(&ctrl->dev,
+                       "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
+                       opc, slave_id, slave_addr, bc + 1);
+       else
+               dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
+                       __func__, slave_id, slave_addr, (int)bc, __buf);
+
+       return rc;
+}
+
+static int spmi_write_cmd(struct spmi_controller *ctrl,
+                         u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
+{
+       struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
+       u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
+       const u8 *buf = __buf;
+       unsigned long flags;
+       u32 cmd, data;
+       int rc;
+       u8 op_code, i;
+
+       if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
+               dev_err(&ctrl->dev,
+                       "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
+                       SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
+               return  -EINVAL;
+       }
+
+       switch (opc) {
+       case SPMI_CMD_WRITE:
+               op_code = SPMI_CMD_REG_WRITE;
+               break;
+       case SPMI_CMD_EXT_WRITE:
+               op_code = SPMI_CMD_EXT_REG_WRITE;
+               break;
+       case SPMI_CMD_EXT_WRITEL:
+               op_code = SPMI_CMD_EXT_REG_WRITE_L;
+               break;
+       default:
+               dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
+               return -EINVAL;
+       }
+
+       cmd = SPMI_APB_SPMI_CMD_EN |
+             (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
+             ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
+             ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
+             ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
+
+       /* Write data to FIFOs */
+       spin_lock_irqsave(&spmi_controller->lock, flags);
+
+       for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
+               data = 0;
+               if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
+                       memcpy(&data, buf, sizeof(data));
+                       buf += sizeof(data);
+               } else {
+                       memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
+                       buf += (bc % SPMI_PER_DATAREG_BYTE);
+               }
+
+               writel((u32 __force)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");
+               ret = -EINVAL;
+               goto err_put_controller;
+       }
+
+       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");
+               ret = -EADDRNOTAVAIL;
+               goto err_put_controller;
+       }
+
+       ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel",
+                                  &spmi_controller->channel);
+       if (ret) {
+               dev_err(&pdev->dev, "can not get channel\n");
+               ret = -ENODEV;
+               goto err_put_controller;
+       }
+
+       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_controller_add failed with error %d!\n", ret);
+               goto err_put_controller;
+       }
+
+       return 0;
+
+err_put_controller:
+       spmi_controller_put(ctrl);
+       return ret;
+}
+
+static int spmi_del_controller(struct platform_device *pdev)
+{
+       struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+
+       spmi_controller_remove(ctrl);
+       spmi_controller_put(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");
index 3ceda03f2864b69760f1616b94ae30bff1ba51da..9f53df9068fee0f9829b601a604f4f43cccf52ae 100644 (file)
@@ -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"
index 42d4861045255bb07cf29c11d114b11d3b671b69..e3108d7dd8490c2d1e9a813f312d64e143f66705 100644 (file)
@@ -1,4 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_SPMI_HISI3670)            += hisi-spmi-controller.o
 obj-$(CONFIG_MFD_HI6421_SPMI)          += hi6421-spmi-pmic.o
diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c
deleted file mode 100644 (file)
index 5bd2326..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-/*
- * SPMI register addr
- */
-#define SPMI_CHANNEL_OFFSET                            0x0300
-#define SPMI_SLAVE_OFFSET                              0x20
-
-#define SPMI_APB_SPMI_CMD_BASE_ADDR                    0x0100
-
-#define SPMI_APB_SPMI_WDATA0_BASE_ADDR                 0x0104
-#define SPMI_APB_SPMI_WDATA1_BASE_ADDR                 0x0108
-#define SPMI_APB_SPMI_WDATA2_BASE_ADDR                 0x010c
-#define SPMI_APB_SPMI_WDATA3_BASE_ADDR                 0x0110
-
-#define SPMI_APB_SPMI_STATUS_BASE_ADDR                 0x0200
-
-#define SPMI_APB_SPMI_RDATA0_BASE_ADDR                 0x0204
-#define SPMI_APB_SPMI_RDATA1_BASE_ADDR                 0x0208
-#define SPMI_APB_SPMI_RDATA2_BASE_ADDR                 0x020c
-#define SPMI_APB_SPMI_RDATA3_BASE_ADDR                 0x0210
-
-#define SPMI_PER_DATAREG_BYTE                          4
-/*
- * SPMI cmd register
- */
-#define SPMI_APB_SPMI_CMD_EN                           BIT(31)
-#define SPMI_APB_SPMI_CMD_TYPE_OFFSET                  24
-#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET                        20
-#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET               16
-#define SPMI_APB_SPMI_CMD_ADDR_OFFSET                  0
-
-/* Command Opcodes */
-
-enum spmi_controller_cmd_op_code {
-       SPMI_CMD_REG_ZERO_WRITE = 0,
-       SPMI_CMD_REG_WRITE = 1,
-       SPMI_CMD_REG_READ = 2,
-       SPMI_CMD_EXT_REG_WRITE = 3,
-       SPMI_CMD_EXT_REG_READ = 4,
-       SPMI_CMD_EXT_REG_WRITE_L = 5,
-       SPMI_CMD_EXT_REG_READ_L = 6,
-       SPMI_CMD_REG_RESET = 7,
-       SPMI_CMD_REG_SLEEP = 8,
-       SPMI_CMD_REG_SHUTDOWN = 9,
-       SPMI_CMD_REG_WAKEUP = 10,
-};
-
-/*
- * SPMI status register
- */
-#define SPMI_APB_TRANS_DONE                    BIT(0)
-#define SPMI_APB_TRANS_FAIL                    BIT(2)
-
-/* Command register fields */
-#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT     16
-
-/* Maximum number of support PMIC peripherals */
-#define SPMI_CONTROLLER_TIMEOUT_US             1000
-#define SPMI_CONTROLLER_MAX_TRANS_BYTES                16
-
-struct spmi_controller_dev {
-       struct spmi_controller  *controller;
-       struct device           *dev;
-       void __iomem            *base;
-       spinlock_t              lock;
-       u32                     channel;
-};
-
-static int spmi_controller_wait_for_done(struct device *dev,
-                                        struct spmi_controller_dev *ctrl_dev,
-                                        void __iomem *base, u8 sid, u16 addr)
-{
-       u32 timeout = SPMI_CONTROLLER_TIMEOUT_US;
-       u32 status, offset;
-
-       offset  = SPMI_APB_SPMI_STATUS_BASE_ADDR;
-       offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid;
-
-       do {
-               status = readl(base + offset);
-
-               if (status & SPMI_APB_TRANS_DONE) {
-                       if (status & SPMI_APB_TRANS_FAIL) {
-                               dev_err(dev, "%s: transaction failed (0x%x)\n",
-                                       __func__, status);
-                               return -EIO;
-                       }
-                       dev_dbg(dev, "%s: status 0x%x\n", __func__, status);
-                       return 0;
-               }
-               udelay(1);
-       } while (timeout--);
-
-       dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status);
-       return -ETIMEDOUT;
-}
-
-static int spmi_read_cmd(struct spmi_controller *ctrl,
-                        u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
-{
-       struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
-       u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
-       unsigned long flags;
-       u8 *buf = __buf;
-       u32 cmd, data;
-       int rc;
-       u8 op_code, i;
-
-       if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-               dev_err(&ctrl->dev,
-                       "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
-                       SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
-               return  -EINVAL;
-       }
-
-       switch (opc) {
-       case SPMI_CMD_READ:
-               op_code = SPMI_CMD_REG_READ;
-               break;
-       case SPMI_CMD_EXT_READ:
-               op_code = SPMI_CMD_EXT_REG_READ;
-               break;
-       case SPMI_CMD_EXT_READL:
-               op_code = SPMI_CMD_EXT_REG_READ_L;
-               break;
-       default:
-               dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
-               return -EINVAL;
-       }
-
-       cmd = SPMI_APB_SPMI_CMD_EN |
-            (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
-            ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
-            ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |  /* slvid */
-            ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
-
-       spin_lock_irqsave(&spmi_controller->lock, flags);
-
-       writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
-
-       rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
-                                          spmi_controller->base, slave_id, slave_addr);
-       if (rc)
-               goto done;
-
-       for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
-               data = readl(spmi_controller->base + chnl_ofst +
-                            SPMI_SLAVE_OFFSET * slave_id +
-                            SPMI_APB_SPMI_RDATA0_BASE_ADDR +
-                            i * SPMI_PER_DATAREG_BYTE);
-               data = be32_to_cpu((__be32 __force)data);
-               if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
-                       memcpy(buf, &data, sizeof(data));
-                       buf += sizeof(data);
-               } else {
-                       memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
-                       buf += (bc % SPMI_PER_DATAREG_BYTE);
-               }
-       }
-
-done:
-       spin_unlock_irqrestore(&spmi_controller->lock, flags);
-       if (rc)
-               dev_err(&ctrl->dev,
-                       "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
-                       opc, slave_id, slave_addr, bc + 1);
-       else
-               dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
-                       __func__, slave_id, slave_addr, (int)bc, __buf);
-
-       return rc;
-}
-
-static int spmi_write_cmd(struct spmi_controller *ctrl,
-                         u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc)
-{
-       struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
-       u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
-       const u8 *buf = __buf;
-       unsigned long flags;
-       u32 cmd, data;
-       int rc;
-       u8 op_code, i;
-
-       if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
-               dev_err(&ctrl->dev,
-                       "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
-                       SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
-               return  -EINVAL;
-       }
-
-       switch (opc) {
-       case SPMI_CMD_WRITE:
-               op_code = SPMI_CMD_REG_WRITE;
-               break;
-       case SPMI_CMD_EXT_WRITE:
-               op_code = SPMI_CMD_EXT_REG_WRITE;
-               break;
-       case SPMI_CMD_EXT_WRITEL:
-               op_code = SPMI_CMD_EXT_REG_WRITE_L;
-               break;
-       default:
-               dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc);
-               return -EINVAL;
-       }
-
-       cmd = SPMI_APB_SPMI_CMD_EN |
-             (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
-             ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
-             ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) |
-             ((slave_addr & 0xffff)  << SPMI_APB_SPMI_CMD_ADDR_OFFSET);
-
-       /* Write data to FIFOs */
-       spin_lock_irqsave(&spmi_controller->lock, flags);
-
-       for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
-               data = 0;
-               if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
-                       memcpy(&data, buf, sizeof(data));
-                       buf += sizeof(data);
-               } else {
-                       memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE);
-                       buf += (bc % SPMI_PER_DATAREG_BYTE);
-               }
-
-               writel((u32 __force)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");
-               ret = -EINVAL;
-               goto err_put_controller;
-       }
-
-       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");
-               ret = -EADDRNOTAVAIL;
-               goto err_put_controller;
-       }
-
-       ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel",
-                                  &spmi_controller->channel);
-       if (ret) {
-               dev_err(&pdev->dev, "can not get channel\n");
-               ret = -ENODEV;
-               goto err_put_controller;
-       }
-
-       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_controller_add failed with error %d!\n", ret);
-               goto err_put_controller;
-       }
-
-       return 0;
-
-err_put_controller:
-       spmi_controller_put(ctrl);
-       return ret;
-}
-
-static int spmi_del_controller(struct platform_device *pdev)
-{
-       struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-
-       spmi_controller_remove(ctrl);
-       spmi_controller_put(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");
index 3b23ad56b31ac984ffad8555f1defc4afdef5aba..d57316c57d7b0df54d628af63361a733cc7b90ef 100644 (file)
@@ -17,7 +17,7 @@ description: |
   node.
 
   The SPMI controller part is provided by
-  drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml.
+  Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
 
 properties:
   $nodename:
diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml
deleted file mode 100644 (file)
index f882903..0000000
+++ /dev/null
@@ -1,73 +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
-  ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
-
-allOf:
-  - $ref: spmi.yaml#
-
-properties:
-
-  $nodename:
-    pattern: "spmi@[0-9a-f]"
-
-  compatible:
-    const: hisilicon,kirin970-spmi-controller
-
-  reg:
-    maxItems: 1
-
-  hisilicon,spmi-channel:
-    $ref: /schemas/types.yaml#/definitions/uint32
-    description: |
-      number of the Kirin 970 SPMI channel where the SPMI devices are connected.
-
-required:
-  - compatible
-  - reg
-  - hisilicon,spmi-channel
-
-patternProperties:
-  "@[0-9a-f]$":
-    type: object
-
-    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.
-
-unevaluatedProperties: false
-
-examples:
-  - |
-    bus {
-      #address-cells = <2>;
-      #size-cells = <2>;
-
-      spmi: spmi@fff24000 {
-        compatible = "hisilicon,kirin970-spmi-controller";
-        #address-cells = <2>;
-        #size-cells = <0>;
-        reg = <0x0 0xfff24000 0x0 0x1000>;
-        hisilicon,spmi-channel = <2>;
-
-        pmic@0 {
-          reg = <0 0>;
-          /* pmic properties */
-        };
-      };
-    };