diff options
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/hikey9xx/Kconfig | 11 | ||||
-rw-r--r-- | drivers/staging/hikey9xx/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/hikey9xx/hisi-spmi-controller.c | 367 | ||||
-rw-r--r-- | drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 2 | ||||
-rw-r--r-- | drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml | 73 |
5 files changed, 1 insertions, 453 deletions
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index 3ceda03f2864..9f53df9068fe 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 42d486104525..e3108d7dd849 100644 --- a/drivers/staging/hikey9xx/Makefile +++ b/drivers/staging/hikey9xx/Makefile @@ -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 index 5bd23262abd6..000000000000 --- a/drivers/staging/hikey9xx/hisi-spmi-controller.c +++ /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"); diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml index 3b23ad56b31a..d57316c57d7b 100644 --- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml +++ b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml @@ -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 index f882903769f9..000000000000 --- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml +++ /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 */ - }; - }; - }; |