This driver is ready for mainstream. So, move it out of staging.
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
---
.../mfd/hisilicon,hi6421-spmi-pmic.yaml | 134 ++++++++
MAINTAINERS | 7 +
drivers/mfd/Kconfig | 16 +
drivers/mfd/Makefile | 1 +
drivers/mfd/hi6421-spmi-pmic.c | 316 ++++++++++++++++++
drivers/staging/Kconfig | 2 -
drivers/staging/Makefile | 1 -
drivers/staging/hikey9xx/Kconfig | 19 --
drivers/staging/hikey9xx/Makefile | 3 -
drivers/staging/hikey9xx/TODO | 5 -
drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 316 ------------------
.../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 134 --------
12 files changed, 474 insertions(+), 480 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/Kconfig
delete mode 100644 drivers/staging/hikey9xx/Makefile
delete mode 100644 drivers/staging/hikey9xx/TODO
delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
delete mode 100644 drivers/staging/hikey9xx/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..8e355cddd437
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -0,0 +1,134 @@
+# 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 <[email protected]>
+
+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
+ Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+
+properties:
+ $nodename:
+ pattern: "pmic@[0-9a-f]"
+
+ compatible:
+ const: hisilicon,hi6421v600-spmi
+
+ reg:
+ maxItems: 1
+
+ '#interrupt-cells':
+ const: 2
+
+ interrupt-controller: true
+
+ gpios:
+ maxItems: 1
+ description: GPIO used for IRQs
+
+ 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 9a69e3810964..89e84b050de6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8291,6 +8291,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 <[email protected]>
+L: [email protected]
+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 <[email protected]>
S: Maintained
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c7f2b100191..99b8da2548b5 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -509,6 +509,22 @@ 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
+ select REGMAP_SPMI
+ 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 4f6d2b8a5f76..e87230fc61ac 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -232,6 +232,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..2b7172560df7
--- /dev/null
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -0,0 +1,316 @@
+// 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/bitops.h>
+#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>
+
+enum hi6421_spmi_pmic_irq_list {
+ OTMP = 0,
+ VBUS_CONNECT,
+ VBUS_DISCONNECT,
+ ALARMON_R,
+ HOLD_6S,
+ HOLD_1S,
+ POWERKEY_UP,
+ POWERKEY_DOWN,
+ OCP_SCP_R,
+ COUL_R,
+ SIM0_HPD_R,
+ SIM0_HPD_F,
+ SIM1_HPD_R,
+ SIM1_HPD_F,
+
+ PMIC_IRQ_LIST_MAX
+};
+
+#define HISI_IRQ_BANK_SIZE 2
+
+/*
+ * IRQ number for the power key button and mask for both UP and DOWN IRQs
+ */
+#define HISI_POWERKEY_IRQ_NUM 0
+#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
+
+/*
+ * Registers for IRQ address and IRQ mask bits
+ *
+ * Please notice that we need to regmap a larger region, as other
+ * registers are used by the regulators.
+ * See drivers/regulator/hi6421-regulator.c.
+ */
+#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
+#define SOC_PMIC_IRQ0_ADDR 0x0212
+
+/*
+ * The IRQs are mapped as:
+ *
+ * ====================== ============= ============ =====
+ * IRQ MASK REGISTER IRQ REGISTER BIT
+ * ====================== ============= ============ =====
+ * OTMP 0x0202 0x212 bit 0
+ * VBUS_CONNECT 0x0202 0x212 bit 1
+ * VBUS_DISCONNECT 0x0202 0x212 bit 2
+ * ALARMON_R 0x0202 0x212 bit 3
+ * HOLD_6S 0x0202 0x212 bit 4
+ * HOLD_1S 0x0202 0x212 bit 5
+ * POWERKEY_UP 0x0202 0x212 bit 6
+ * POWERKEY_DOWN 0x0202 0x212 bit 7
+ *
+ * OCP_SCP_R 0x0203 0x213 bit 0
+ * COUL_R 0x0203 0x213 bit 1
+ * SIM0_HPD_R 0x0203 0x213 bit 2
+ * SIM0_HPD_F 0x0203 0x213 bit 3
+ * SIM1_HPD_R 0x0203 0x213 bit 4
+ * SIM1_HPD_F 0x0203 0x213 bit 5
+ * ====================== ============= ============ =====
+ *
+ * Each mask register contains 8 bits. The ancillary macros below
+ * convert a number from 0 to 14 into a register address and a bit mask
+ */
+#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
+ (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
+#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
+#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
+
+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 *ddata = (struct hi6421_spmi_pmic *)priv;
+ unsigned long pending;
+ unsigned int in;
+ int i, offset;
+
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
+
+ /* Mark pending IRQs as handled */
+ pending = HISI_8BITS_MASK & in;
+ regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, pending);
+
+ if (i == HISI_POWERKEY_IRQ_NUM &&
+ (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
+ /*
+ * If both powerkey down and up IRQs are received,
+ * handle them at the right order
+ */
+ generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
+ generic_handle_irq(ddata->irqs[POWERKEY_UP]);
+ pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
+ }
+
+ if (!pending)
+ continue;
+
+ for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
+ generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hi6421_spmi_irq_mask(struct irq_data *d)
+{
+ struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ unsigned int data;
+ u32 offset;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&ddata->lock, flags);
+
+ regmap_read(ddata->regmap, offset, &data);
+ data |= HISI_IRQ_MASK_BIT(d);
+ regmap_write(ddata->regmap, offset, data);
+
+ spin_unlock_irqrestore(&ddata->lock, flags);
+}
+
+static void hi6421_spmi_irq_unmask(struct irq_data *d)
+{
+ struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+ unsigned long flags;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&ddata->lock, flags);
+
+ regmap_read(ddata->regmap, offset, &data);
+ data &= ~HISI_IRQ_MASK_BIT(d);
+ regmap_write(ddata->regmap, offset, data);
+
+ spin_unlock_irqrestore(&ddata->lock, flags);
+}
+
+static struct irq_chip hi6421_spmi_pmu_irqchip = {
+ .name = "hi6421v600-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 *ddata = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
+ handle_simple_irq, "hi6421v600");
+ irq_set_chip_data(virq, ddata);
+ 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_init(struct hi6421_spmi_pmic *ddata)
+{
+ int i;
+ unsigned int pending;
+
+ /* Mask all IRQs */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
+ regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
+ HISI_8BITS_MASK);
+
+ /* Mark all IRQs as handled */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
+ regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
+ HISI_8BITS_MASK);
+ }
+}
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 16,
+ .val_bits = BITS_PER_BYTE,
+ .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 *ddata;
+ unsigned int virq;
+ int ret, i;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ ddata->regmap = devm_regmap_init_spmi_ext(pdev, ®map_config);
+ if (IS_ERR(ddata->regmap))
+ return PTR_ERR(ddata->regmap);
+
+ spin_lock_init(&ddata->lock);
+
+ ddata->dev = dev;
+
+ ddata->gpio = of_get_gpio(np, 0);
+ if (ddata->gpio < 0)
+ return ddata->gpio;
+
+ if (!gpio_is_valid(ddata->gpio))
+ return -EINVAL;
+
+ ret = devm_gpio_request_one(dev, ddata->gpio, GPIOF_IN, "pmic");
+ if (ret < 0) {
+ dev_err(dev, "Failed to request gpio%d\n", ddata->gpio);
+ return ret;
+ }
+
+ ddata->irq = gpio_to_irq(ddata->gpio);
+
+ hi6421_spmi_pmic_irq_init(ddata);
+
+ ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
+ if (!ddata->irqs)
+ return -ENOMEM;
+
+ ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
+ &hi6421_spmi_domain_ops, ddata);
+ if (!ddata->domain) {
+ dev_err(dev, "Failed to create IRQ domain\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
+ virq = irq_create_mapping(ddata->domain, i);
+ if (!virq) {
+ dev_err(dev, "Failed to map H/W IRQ\n");
+ return -ENOSPC;
+ }
+ ddata->irqs[i] = virq;
+ }
+
+ ret = request_threaded_irq(ddata->irq, hi6421_spmi_irq_handler, NULL,
+ IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pmic", ddata);
+ if (ret < 0) {
+ dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
+ ret);
+ return ret;
+ }
+
+ dev_set_drvdata(&pdev->dev, ddata);
+
+ ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+ hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
+ NULL, 0, NULL);
+ if (ret < 0)
+ dev_err(dev, "Failed to add child devices: %d\n", ret);
+
+ return ret;
+}
+
+static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
+{
+ struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
+
+ free_irq(ddata->irq, ddata);
+}
+
+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/Kconfig b/drivers/staging/Kconfig
index b7ae5bdc4eb5..5b4267d3ed6b 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -104,6 +104,4 @@ source "drivers/staging/qlge/Kconfig"
source "drivers/staging/wfx/Kconfig"
-source "drivers/staging/hikey9xx/Kconfig"
-
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 075c979bfe7c..7179cdcaafe7 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -42,4 +42,3 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_KPC2000) += kpc2000/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_WFX) += wfx/
-obj-y += hikey9xx/
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
deleted file mode 100644
index 9f53df9068fe..000000000000
--- a/drivers/staging/hikey9xx/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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 HAS_IOMEM
- depends on OF
- depends on SPMI
- select MFD_CORE
- select REGMAP_SPMI
- 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.
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
deleted file mode 100644
index e3108d7dd849..000000000000
--- a/drivers/staging/hikey9xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
diff --git a/drivers/staging/hikey9xx/TODO b/drivers/staging/hikey9xx/TODO
deleted file mode 100644
index 65e7996a3066..000000000000
--- a/drivers/staging/hikey9xx/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-ToDo list:
-
-- Port other drivers needed by Hikey 960/970;
-- Test drivers on Hikey 960;
-- Validate device tree bindings.
diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
deleted file mode 100644
index 2b7172560df7..000000000000
--- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
+++ /dev/null
@@ -1,316 +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/bitops.h>
-#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>
-
-enum hi6421_spmi_pmic_irq_list {
- OTMP = 0,
- VBUS_CONNECT,
- VBUS_DISCONNECT,
- ALARMON_R,
- HOLD_6S,
- HOLD_1S,
- POWERKEY_UP,
- POWERKEY_DOWN,
- OCP_SCP_R,
- COUL_R,
- SIM0_HPD_R,
- SIM0_HPD_F,
- SIM1_HPD_R,
- SIM1_HPD_F,
-
- PMIC_IRQ_LIST_MAX
-};
-
-#define HISI_IRQ_BANK_SIZE 2
-
-/*
- * IRQ number for the power key button and mask for both UP and DOWN IRQs
- */
-#define HISI_POWERKEY_IRQ_NUM 0
-#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
-
-/*
- * Registers for IRQ address and IRQ mask bits
- *
- * Please notice that we need to regmap a larger region, as other
- * registers are used by the regulators.
- * See drivers/regulator/hi6421-regulator.c.
- */
-#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
-#define SOC_PMIC_IRQ0_ADDR 0x0212
-
-/*
- * The IRQs are mapped as:
- *
- * ====================== ============= ============ =====
- * IRQ MASK REGISTER IRQ REGISTER BIT
- * ====================== ============= ============ =====
- * OTMP 0x0202 0x212 bit 0
- * VBUS_CONNECT 0x0202 0x212 bit 1
- * VBUS_DISCONNECT 0x0202 0x212 bit 2
- * ALARMON_R 0x0202 0x212 bit 3
- * HOLD_6S 0x0202 0x212 bit 4
- * HOLD_1S 0x0202 0x212 bit 5
- * POWERKEY_UP 0x0202 0x212 bit 6
- * POWERKEY_DOWN 0x0202 0x212 bit 7
- *
- * OCP_SCP_R 0x0203 0x213 bit 0
- * COUL_R 0x0203 0x213 bit 1
- * SIM0_HPD_R 0x0203 0x213 bit 2
- * SIM0_HPD_F 0x0203 0x213 bit 3
- * SIM1_HPD_R 0x0203 0x213 bit 4
- * SIM1_HPD_F 0x0203 0x213 bit 5
- * ====================== ============= ============ =====
- *
- * Each mask register contains 8 bits. The ancillary macros below
- * convert a number from 0 to 14 into a register address and a bit mask
- */
-#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
- (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
-#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
-#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
-
-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 *ddata = (struct hi6421_spmi_pmic *)priv;
- unsigned long pending;
- unsigned int in;
- int i, offset;
-
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
- regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
-
- /* Mark pending IRQs as handled */
- pending = HISI_8BITS_MASK & in;
- regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, pending);
-
- if (i == HISI_POWERKEY_IRQ_NUM &&
- (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
- /*
- * If both powerkey down and up IRQs are received,
- * handle them at the right order
- */
- generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
- generic_handle_irq(ddata->irqs[POWERKEY_UP]);
- pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
- }
-
- if (!pending)
- continue;
-
- for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
- generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-static void hi6421_spmi_irq_mask(struct irq_data *d)
-{
- struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
- unsigned long flags;
- unsigned int data;
- u32 offset;
-
- offset = HISI_IRQ_MASK_REG(d);
-
- spin_lock_irqsave(&ddata->lock, flags);
-
- regmap_read(ddata->regmap, offset, &data);
- data |= HISI_IRQ_MASK_BIT(d);
- regmap_write(ddata->regmap, offset, data);
-
- spin_unlock_irqrestore(&ddata->lock, flags);
-}
-
-static void hi6421_spmi_irq_unmask(struct irq_data *d)
-{
- struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
- u32 data, offset;
- unsigned long flags;
-
- offset = HISI_IRQ_MASK_REG(d);
-
- spin_lock_irqsave(&ddata->lock, flags);
-
- regmap_read(ddata->regmap, offset, &data);
- data &= ~HISI_IRQ_MASK_BIT(d);
- regmap_write(ddata->regmap, offset, data);
-
- spin_unlock_irqrestore(&ddata->lock, flags);
-}
-
-static struct irq_chip hi6421_spmi_pmu_irqchip = {
- .name = "hi6421v600-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 *ddata = d->host_data;
-
- irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
- handle_simple_irq, "hi6421v600");
- irq_set_chip_data(virq, ddata);
- 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_init(struct hi6421_spmi_pmic *ddata)
-{
- int i;
- unsigned int pending;
-
- /* Mask all IRQs */
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
- regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
- HISI_8BITS_MASK);
-
- /* Mark all IRQs as handled */
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
- regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
- regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
- HISI_8BITS_MASK);
- }
-}
-
-static const struct regmap_config regmap_config = {
- .reg_bits = 16,
- .val_bits = BITS_PER_BYTE,
- .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 *ddata;
- unsigned int virq;
- int ret, i;
-
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
-
- ddata->regmap = devm_regmap_init_spmi_ext(pdev, ®map_config);
- if (IS_ERR(ddata->regmap))
- return PTR_ERR(ddata->regmap);
-
- spin_lock_init(&ddata->lock);
-
- ddata->dev = dev;
-
- ddata->gpio = of_get_gpio(np, 0);
- if (ddata->gpio < 0)
- return ddata->gpio;
-
- if (!gpio_is_valid(ddata->gpio))
- return -EINVAL;
-
- ret = devm_gpio_request_one(dev, ddata->gpio, GPIOF_IN, "pmic");
- if (ret < 0) {
- dev_err(dev, "Failed to request gpio%d\n", ddata->gpio);
- return ret;
- }
-
- ddata->irq = gpio_to_irq(ddata->gpio);
-
- hi6421_spmi_pmic_irq_init(ddata);
-
- ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
- if (!ddata->irqs)
- return -ENOMEM;
-
- ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
- &hi6421_spmi_domain_ops, ddata);
- if (!ddata->domain) {
- dev_err(dev, "Failed to create IRQ domain\n");
- return -ENODEV;
- }
-
- for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
- virq = irq_create_mapping(ddata->domain, i);
- if (!virq) {
- dev_err(dev, "Failed to map H/W IRQ\n");
- return -ENOSPC;
- }
- ddata->irqs[i] = virq;
- }
-
- ret = request_threaded_irq(ddata->irq, hi6421_spmi_irq_handler, NULL,
- IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
- "pmic", ddata);
- if (ret < 0) {
- dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
- ret);
- return ret;
- }
-
- dev_set_drvdata(&pdev->dev, ddata);
-
- ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
- hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
- NULL, 0, NULL);
- if (ret < 0)
- dev_err(dev, "Failed to add child devices: %d\n", ret);
-
- return ret;
-}
-
-static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
-{
- struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
-
- free_irq(ddata->irq, ddata);
-}
-
-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 8e355cddd437..000000000000
--- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
+++ /dev/null
@@ -1,134 +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 <[email protected]>
-
-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
- Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
-
-properties:
- $nodename:
- pattern: "pmic@[0-9a-f]"
-
- compatible:
- const: hisilicon,hi6421v600-spmi
-
- reg:
- maxItems: 1
-
- '#interrupt-cells':
- const: 2
-
- interrupt-controller: true
-
- gpios:
- maxItems: 1
- description: GPIO used for IRQs
-
- 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.31.1
On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
>
> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
> ---
> .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 134 ++++++++
> MAINTAINERS | 7 +
> drivers/mfd/Kconfig | 16 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/hi6421-spmi-pmic.c | 316 ++++++++++++++++++
> drivers/staging/Kconfig | 2 -
> drivers/staging/Makefile | 1 -
> drivers/staging/hikey9xx/Kconfig | 19 --
> drivers/staging/hikey9xx/Makefile | 3 -
> drivers/staging/hikey9xx/TODO | 5 -
> drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 316 ------------------
> .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 134 --------
> 12 files changed, 474 insertions(+), 480 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/Kconfig
> delete mode 100644 drivers/staging/hikey9xx/Makefile
> delete mode 100644 drivers/staging/hikey9xx/TODO
> delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/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..8e355cddd437
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> @@ -0,0 +1,134 @@
> +# 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 <[email protected]>
> +
> +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
> + Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> +
> +properties:
> + $nodename:
> + pattern: "pmic@[0-9a-f]"
> +
> + compatible:
> + const: hisilicon,hi6421v600-spmi
> +
> + reg:
> + maxItems: 1
> +
> + '#interrupt-cells':
> + const: 2
> +
> + interrupt-controller: true
> +
> + gpios:
> + maxItems: 1
> + description: GPIO used for IRQs
> +
> + 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 9a69e3810964..89e84b050de6 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8291,6 +8291,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 <[email protected]>
> +L: [email protected]
> +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 <[email protected]>
> S: Maintained
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 5c7f2b100191..99b8da2548b5 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -509,6 +509,22 @@ 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
> + select REGMAP_SPMI
> + 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 4f6d2b8a5f76..e87230fc61ac 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -232,6 +232,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..2b7172560df7
> --- /dev/null
> +++ b/drivers/mfd/hi6421-spmi-pmic.c
> @@ -0,0 +1,316 @@
> +// 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
Can this be updated?
> + */
> +
> +#include <linux/bitops.h>
> +#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>
> +
> +enum hi6421_spmi_pmic_irq_list {
> + OTMP = 0,
> + VBUS_CONNECT,
> + VBUS_DISCONNECT,
> + ALARMON_R,
> + HOLD_6S,
> + HOLD_1S,
> + POWERKEY_UP,
> + POWERKEY_DOWN,
> + OCP_SCP_R,
> + COUL_R,
> + SIM0_HPD_R,
> + SIM0_HPD_F,
> + SIM1_HPD_R,
> + SIM1_HPD_F,
> +
> + PMIC_IRQ_LIST_MAX
> +};
> +
> +#define HISI_IRQ_BANK_SIZE 2
> +
> +/*
> + * IRQ number for the power key button and mask for both UP and DOWN IRQs
> + */
> +#define HISI_POWERKEY_IRQ_NUM 0
> +#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
> +
> +/*
> + * Registers for IRQ address and IRQ mask bits
> + *
> + * Please notice that we need to regmap a larger region, as other
> + * registers are used by the regulators.
> + * See drivers/regulator/hi6421-regulator.c.
> + */
> +#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
> +#define SOC_PMIC_IRQ0_ADDR 0x0212
> +
> +/*
> + * The IRQs are mapped as:
> + *
> + * ====================== ============= ============ =====
> + * IRQ MASK REGISTER IRQ REGISTER BIT
> + * ====================== ============= ============ =====
> + * OTMP 0x0202 0x212 bit 0
> + * VBUS_CONNECT 0x0202 0x212 bit 1
> + * VBUS_DISCONNECT 0x0202 0x212 bit 2
> + * ALARMON_R 0x0202 0x212 bit 3
> + * HOLD_6S 0x0202 0x212 bit 4
> + * HOLD_1S 0x0202 0x212 bit 5
> + * POWERKEY_UP 0x0202 0x212 bit 6
> + * POWERKEY_DOWN 0x0202 0x212 bit 7
> + *
> + * OCP_SCP_R 0x0203 0x213 bit 0
> + * COUL_R 0x0203 0x213 bit 1
> + * SIM0_HPD_R 0x0203 0x213 bit 2
> + * SIM0_HPD_F 0x0203 0x213 bit 3
> + * SIM1_HPD_R 0x0203 0x213 bit 4
> + * SIM1_HPD_F 0x0203 0x213 bit 5
> + * ====================== ============= ============ =====
> + *
> + * Each mask register contains 8 bits. The ancillary macros below
> + * convert a number from 0 to 14 into a register address and a bit mask
> + */
> +#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
> + (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
> +#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
> +#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
Are these lines up in real code? Looks like they're not in the diff.
HISI_8BITS_MASK is just 0xff right? I think we're more used to seeing
the value used in place. Creating a macro for it out of GENMASK is
probably slightly over-engineering it a little.
> +static const struct mfd_cell hi6421v600_devs[] = {
> + { .name = "hi6421v600-regulator", },
> +};
Where are the other devices?
> +static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
> +{
> + struct hi6421_spmi_pmic *ddata = (struct hi6421_spmi_pmic *)priv;
> + unsigned long pending;
> + unsigned int in;
> + int i, offset;
> +
> + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
> + regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
> +
> + /* Mark pending IRQs as handled */
> + pending = HISI_8BITS_MASK & in;
It looks odd to see them this way around.
Usually mark the value with the mask, not the mask with the value.
> + regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, pending);
> +
> + if (i == HISI_POWERKEY_IRQ_NUM &&
> + (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
> + /*
> + * If both powerkey down and up IRQs are received,
> + * handle them at the right order
> + */
> + generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
> + generic_handle_irq(ddata->irqs[POWERKEY_UP]);
> + pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
> + }
> +
> + if (!pending)
> + continue;
> +
> + for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
> + generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
> + }
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void hi6421_spmi_irq_mask(struct irq_data *d)
> +{
> + struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
> + unsigned long flags;
> + unsigned int data;
> + u32 offset;
> +
> + offset = HISI_IRQ_MASK_REG(d);
> +
> + spin_lock_irqsave(&ddata->lock, flags);
> +
> + regmap_read(ddata->regmap, offset, &data);
> + data |= HISI_IRQ_MASK_BIT(d);
> + regmap_write(ddata->regmap, offset, data);
> +
> + spin_unlock_irqrestore(&ddata->lock, flags);
> +}
> +
> +static void hi6421_spmi_irq_unmask(struct irq_data *d)
> +{
> + struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
> + u32 data, offset;
> + unsigned long flags;
> +
> + offset = HISI_IRQ_MASK_REG(d);
> +
> + spin_lock_irqsave(&ddata->lock, flags);
> +
> + regmap_read(ddata->regmap, offset, &data);
> + data &= ~HISI_IRQ_MASK_BIT(d);
> + regmap_write(ddata->regmap, offset, data);
> +
> + spin_unlock_irqrestore(&ddata->lock, flags);
> +}
> +
> +static struct irq_chip hi6421_spmi_pmu_irqchip = {
> + .name = "hi6421v600-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 *ddata = d->host_data;
> +
> + irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
> + handle_simple_irq, "hi6421v600");
> + irq_set_chip_data(virq, ddata);
> + 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_init(struct hi6421_spmi_pmic *ddata)
> +{
> + int i;
> + unsigned int pending;
> +
> + /* Mask all IRQs */
> + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
> + regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
> + HISI_8BITS_MASK);
> +
> + /* Mark all IRQs as handled */
> + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
> + regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
> + regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
> + HISI_8BITS_MASK);
> + }
> +}
> +
> +static const struct regmap_config regmap_config = {
> + .reg_bits = 16,
> + .val_bits = BITS_PER_BYTE,
> + .max_register = 0xffff,
> + .fast_io = true
> +};
Why are these tabbed out this far? Legacy?
> +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 *ddata;
> + unsigned int virq;
> + int ret, i;
> +
> + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
> + if (!ddata)
> + return -ENOMEM;
> +
> + ddata->regmap = devm_regmap_init_spmi_ext(pdev, ®map_config);
> + if (IS_ERR(ddata->regmap))
> + return PTR_ERR(ddata->regmap);
> +
> + spin_lock_init(&ddata->lock);
> +
> + ddata->dev = dev;
> +
> + ddata->gpio = of_get_gpio(np, 0);
> + if (ddata->gpio < 0)
> + return ddata->gpio;
> +
> + if (!gpio_is_valid(ddata->gpio))
> + return -EINVAL;
> +
> + ret = devm_gpio_request_one(dev, ddata->gpio, GPIOF_IN, "pmic");
> + if (ret < 0) {
> + dev_err(dev, "Failed to request gpio%d\n", ddata->gpio);
> + return ret;
> + }
> +
> + ddata->irq = gpio_to_irq(ddata->gpio);
> +
> + hi6421_spmi_pmic_irq_init(ddata);
> +
> + ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
> + if (!ddata->irqs)
> + return -ENOMEM;
> +
> + ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
> + &hi6421_spmi_domain_ops, ddata);
> + if (!ddata->domain) {
> + dev_err(dev, "Failed to create IRQ domain\n");
> + return -ENODEV;
> + }
> +
> + for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
> + virq = irq_create_mapping(ddata->domain, i);
> + if (!virq) {
> + dev_err(dev, "Failed to map H/W IRQ\n");
> + return -ENOSPC;
-ENOSPC doesn't seem right here.
Can't find any other uses of it for irq_create_mapping() either.
> + }
> + ddata->irqs[i] = virq;
> + }
> +
> + ret = request_threaded_irq(ddata->irq, hi6421_spmi_irq_handler, NULL,
> + IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
> + "pmic", ddata);
> + if (ret < 0) {
> + dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
> + ret);
> + return ret;
> + }
> +
> + dev_set_drvdata(&pdev->dev, ddata);
> +
> + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> + hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
> + NULL, 0, NULL);
> + if (ret < 0)
> + dev_err(dev, "Failed to add child devices: %d\n", ret);
> +
> + return ret;
> +}
> +
> +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> +{
> + struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
> +
> + free_irq(ddata->irq, ddata);
No devm_* version?
> +}
> +
> +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");
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
Em Thu, 24 Jun 2021 12:33:28 +0100
Lee Jones <[email protected]> escreveu:
> On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
>
> > This driver is ready for mainstream. So, move it out of staging.
> >
> > Signed-off-by: Mauro Carvalho Chehab <[email protected]>
> > ---
> > .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 134 ++++++++
> > MAINTAINERS | 7 +
> > drivers/mfd/Kconfig | 16 +
> > drivers/mfd/Makefile | 1 +
> > drivers/mfd/hi6421-spmi-pmic.c | 316 ++++++++++++++++++
> > drivers/staging/Kconfig | 2 -
> > drivers/staging/Makefile | 1 -
> > drivers/staging/hikey9xx/Kconfig | 19 --
> > drivers/staging/hikey9xx/Makefile | 3 -
> > drivers/staging/hikey9xx/TODO | 5 -
> > drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 316 ------------------
> > .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 134 --------
> > 12 files changed, 474 insertions(+), 480 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/Kconfig
> > delete mode 100644 drivers/staging/hikey9xx/Makefile
> > delete mode 100644 drivers/staging/hikey9xx/TODO
> > delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> > delete mode 100644 drivers/staging/hikey9xx/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..8e355cddd437
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> > @@ -0,0 +1,134 @@
> > +# 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 <[email protected]>
> > +
> > +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
> > + Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> > +
> > +properties:
> > + $nodename:
> > + pattern: "pmic@[0-9a-f]"
> > +
> > + compatible:
> > + const: hisilicon,hi6421v600-spmi
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + '#interrupt-cells':
> > + const: 2
> > +
> > + interrupt-controller: true
> > +
> > + gpios:
> > + maxItems: 1
> > + description: GPIO used for IRQs
> > +
> > + 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 9a69e3810964..89e84b050de6 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -8291,6 +8291,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 <[email protected]>
> > +L: [email protected]
> > +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 <[email protected]>
> > S: Maintained
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index 5c7f2b100191..99b8da2548b5 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -509,6 +509,22 @@ 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
> > + select REGMAP_SPMI
> > + 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 4f6d2b8a5f76..e87230fc61ac 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -232,6 +232,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..2b7172560df7
> > --- /dev/null
> > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > @@ -0,0 +1,316 @@
> > +// 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
>
> Can this be updated?
Do you mean updating the copyrights to cover this year? E.g.
something like this:
* Copyright (c) 2013-2021 Linaro Ltd.
* Copyright (c) 2011-2021 Hisilicon.
* Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
Right? Or are you meaning something else?
Btw, this device is a variant of the already-existing devices
provided by the hi6421-pmic-core, which has:
* Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
* http://www.hisilicon.com
* Copyright (c) <2013-2017> Linaro Ltd.
* https://www.linaro.org
*
The main difference is that this device is connected via a
SPMI bus (there are other differences on register settings and
LDO/BUCK regulators).
>
> > + */
> > +
> > +#include <linux/bitops.h>
> > +#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>
> > +
> > +enum hi6421_spmi_pmic_irq_list {
> > + OTMP = 0,
> > + VBUS_CONNECT,
> > + VBUS_DISCONNECT,
> > + ALARMON_R,
> > + HOLD_6S,
> > + HOLD_1S,
> > + POWERKEY_UP,
> > + POWERKEY_DOWN,
> > + OCP_SCP_R,
> > + COUL_R,
> > + SIM0_HPD_R,
> > + SIM0_HPD_F,
> > + SIM1_HPD_R,
> > + SIM1_HPD_F,
> > +
> > + PMIC_IRQ_LIST_MAX
> > +};
> > +
> > +#define HISI_IRQ_BANK_SIZE 2
> > +
> > +/*
> > + * IRQ number for the power key button and mask for both UP and DOWN IRQs
> > + */
> > +#define HISI_POWERKEY_IRQ_NUM 0
> > +#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
> > +
> > +/*
> > + * Registers for IRQ address and IRQ mask bits
> > + *
> > + * Please notice that we need to regmap a larger region, as other
> > + * registers are used by the regulators.
> > + * See drivers/regulator/hi6421-regulator.c.
> > + */
> > +#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
> > +#define SOC_PMIC_IRQ0_ADDR 0x0212
> > +
> > +/*
> > + * The IRQs are mapped as:
> > + *
> > + * ====================== ============= ============ =====
> > + * IRQ MASK REGISTER IRQ REGISTER BIT
> > + * ====================== ============= ============ =====
> > + * OTMP 0x0202 0x212 bit 0
> > + * VBUS_CONNECT 0x0202 0x212 bit 1
> > + * VBUS_DISCONNECT 0x0202 0x212 bit 2
> > + * ALARMON_R 0x0202 0x212 bit 3
> > + * HOLD_6S 0x0202 0x212 bit 4
> > + * HOLD_1S 0x0202 0x212 bit 5
> > + * POWERKEY_UP 0x0202 0x212 bit 6
> > + * POWERKEY_DOWN 0x0202 0x212 bit 7
> > + *
> > + * OCP_SCP_R 0x0203 0x213 bit 0
> > + * COUL_R 0x0203 0x213 bit 1
> > + * SIM0_HPD_R 0x0203 0x213 bit 2
> > + * SIM0_HPD_F 0x0203 0x213 bit 3
> > + * SIM1_HPD_R 0x0203 0x213 bit 4
> > + * SIM1_HPD_F 0x0203 0x213 bit 5
> > + * ====================== ============= ============ =====
> > + *
> > + * Each mask register contains 8 bits. The ancillary macros below
> > + * convert a number from 0 to 14 into a register address and a bit mask
> > + */
> > +#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
> > + (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
> > +#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
> > +#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
>
> Are these lines up in real code? Looks like they're not in the diff.
Weird. The changes to use those are at patch 3/8. All the above
macros are used at the patch.
>
> HISI_8BITS_MASK is just 0xff right? I think we're more used to seeing
> the value used in place. Creating a macro for it out of GENMASK is
> probably slightly over-engineering it a little.
Ok, I'll replace it to 0xff everywhere. I guess we added it due to
some previous review.
>
> > +static const struct mfd_cell hi6421v600_devs[] = {
> > + { .name = "hi6421v600-regulator", },
> > +};
>
> Where are the other devices?
While this is a MFD device, as it has regulators, ADC and other
stuff, right now, only the regulator and the IRQs are implemented.
The IRQs are at the core of this driver, while the regulator
is at the separate regulator driver.
>
> > +static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
> > +{
> > + struct hi6421_spmi_pmic *ddata = (struct hi6421_spmi_pmic *)priv;
> > + unsigned long pending;
> > + unsigned int in;
> > + int i, offset;
> > +
> > + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
> > + regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
> > +
> > + /* Mark pending IRQs as handled */
> > + pending = HISI_8BITS_MASK & in;
>
> It looks odd to see them this way around.
>
> Usually mark the value with the mask, not the mask with the value.
Yeah, I guess we can simply drop this line.
>
> > + regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, pending);
> > +
> > + if (i == HISI_POWERKEY_IRQ_NUM &&
> > + (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
> > + /*
> > + * If both powerkey down and up IRQs are received,
> > + * handle them at the right order
> > + */
> > + generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
> > + generic_handle_irq(ddata->irqs[POWERKEY_UP]);
> > + pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
> > + }
> > +
> > + if (!pending)
> > + continue;
> > +
> > + for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
> > + generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
> > + }
> > + }
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static void hi6421_spmi_irq_mask(struct irq_data *d)
> > +{
> > + struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
> > + unsigned long flags;
> > + unsigned int data;
> > + u32 offset;
> > +
> > + offset = HISI_IRQ_MASK_REG(d);
> > +
> > + spin_lock_irqsave(&ddata->lock, flags);
> > +
> > + regmap_read(ddata->regmap, offset, &data);
> > + data |= HISI_IRQ_MASK_BIT(d);
> > + regmap_write(ddata->regmap, offset, data);
> > +
> > + spin_unlock_irqrestore(&ddata->lock, flags);
> > +}
> > +
> > +static void hi6421_spmi_irq_unmask(struct irq_data *d)
> > +{
> > + struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
> > + u32 data, offset;
> > + unsigned long flags;
> > +
> > + offset = HISI_IRQ_MASK_REG(d);
> > +
> > + spin_lock_irqsave(&ddata->lock, flags);
> > +
> > + regmap_read(ddata->regmap, offset, &data);
> > + data &= ~HISI_IRQ_MASK_BIT(d);
> > + regmap_write(ddata->regmap, offset, data);
> > +
> > + spin_unlock_irqrestore(&ddata->lock, flags);
> > +}
> > +
> > +static struct irq_chip hi6421_spmi_pmu_irqchip = {
> > + .name = "hi6421v600-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 *ddata = d->host_data;
> > +
> > + irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
> > + handle_simple_irq, "hi6421v600");
> > + irq_set_chip_data(virq, ddata);
> > + 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_init(struct hi6421_spmi_pmic *ddata)
> > +{
> > + int i;
> > + unsigned int pending;
> > +
> > + /* Mask all IRQs */
> > + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
> > + regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
> > + HISI_8BITS_MASK);
> > +
> > + /* Mark all IRQs as handled */
> > + for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
> > + regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
> > + regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
> > + HISI_8BITS_MASK);
> > + }
> > +}
> > +
> > +static const struct regmap_config regmap_config = {
> > + .reg_bits = 16,
> > + .val_bits = BITS_PER_BYTE,
> > + .max_register = 0xffff,
> > + .fast_io = true
> > +};
>
> Why are these tabbed out this far? Legacy?
No particular reason. This is not legacy, as the conversion to
regmap was done after a review request. I guess it is probably
due to copy-and-paste from some other driver.
Anyway, I'll adjust it, using just one tab instead of two.
>
> > +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 *ddata;
> > + unsigned int virq;
> > + int ret, i;
> > +
> > + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
> > + if (!ddata)
> > + return -ENOMEM;
> > +
> > + ddata->regmap = devm_regmap_init_spmi_ext(pdev, ®map_config);
> > + if (IS_ERR(ddata->regmap))
> > + return PTR_ERR(ddata->regmap);
> > +
> > + spin_lock_init(&ddata->lock);
> > +
> > + ddata->dev = dev;
> > +
> > + ddata->gpio = of_get_gpio(np, 0);
> > + if (ddata->gpio < 0)
> > + return ddata->gpio;
> > +
> > + if (!gpio_is_valid(ddata->gpio))
> > + return -EINVAL;
> > +
> > + ret = devm_gpio_request_one(dev, ddata->gpio, GPIOF_IN, "pmic");
> > + if (ret < 0) {
> > + dev_err(dev, "Failed to request gpio%d\n", ddata->gpio);
> > + return ret;
> > + }
> > +
> > + ddata->irq = gpio_to_irq(ddata->gpio);
> > +
> > + hi6421_spmi_pmic_irq_init(ddata);
> > +
> > + ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
> > + if (!ddata->irqs)
> > + return -ENOMEM;
> > +
> > + ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
> > + &hi6421_spmi_domain_ops, ddata);
> > + if (!ddata->domain) {
> > + dev_err(dev, "Failed to create IRQ domain\n");
> > + return -ENODEV;
> > + }
> > +
> > + for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
> > + virq = irq_create_mapping(ddata->domain, i);
> > + if (!virq) {
> > + dev_err(dev, "Failed to map H/W IRQ\n");
> > + return -ENOSPC;
>
> -ENOSPC doesn't seem right here.
>
> Can't find any other uses of it for irq_create_mapping() either.
There are two drivers returning -ENOSPC:
arch/powerpc/platforms/pseries/msi.c
arch/powerpc/sysdev/mpic_u3msi.c
But others return -EIO, -EINVAL, -ENOMEM, -ENODEV, -ENXIO.
I think that -ENODEV would fit better here.
>
> > + }
> > + ddata->irqs[i] = virq;
> > + }
> > +
> > + ret = request_threaded_irq(ddata->irq, hi6421_spmi_irq_handler, NULL,
> > + IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
> > + "pmic", ddata);
> > + if (ret < 0) {
> > + dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
> > + ret);
> > + return ret;
> > + }
> > +
> > + dev_set_drvdata(&pdev->dev, ddata);
> > +
> > + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> > + hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
> > + NULL, 0, NULL);
> > + if (ret < 0)
> > + dev_err(dev, "Failed to add child devices: %d\n", ret);
> > +
> > + return ret;
> > +}
> > +
> > +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> > +{
> > + struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
> > +
> > + free_irq(ddata->irq, ddata);
>
> No devm_* version?
Are there a devm_* variant for gpio_to_irq()?
>
> > +}
> > +
> > +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");
>
Thanks,
Mauro
On Thu, Jun 24, 2021 at 02:36:05PM +0200, Mauro Carvalho Chehab wrote:
> Em Thu, 24 Jun 2021 12:33:28 +0100
> Lee Jones <[email protected]> escreveu:
>
> > On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> > > +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> > > +{
> > > + struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
> > > +
> > > + free_irq(ddata->irq, ddata);
> >
> > No devm_* version?
>
> Are there a devm_* variant for gpio_to_irq()?
>
It's the request_threaded_irq() which needs unwound not the gpio_to_irq()
so you could use devm_request_threaded_irq().
Using the devm_ version would fix a leak in probe which Smatch is
supposed to find but does not. :(
regards,
dan carpenter
On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> Em Thu, 24 Jun 2021 12:33:28 +0100
> Lee Jones <[email protected]> escreveu:
>
> > On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> >
> > > This driver is ready for mainstream. So, move it out of staging.
> > >
> > > Signed-off-by: Mauro Carvalho Chehab <[email protected]>
> > > ---
> > > .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 134 ++++++++
> > > MAINTAINERS | 7 +
> > > drivers/mfd/Kconfig | 16 +
> > > drivers/mfd/Makefile | 1 +
> > > drivers/mfd/hi6421-spmi-pmic.c | 316 ++++++++++++++++++
> > > drivers/staging/Kconfig | 2 -
> > > drivers/staging/Makefile | 1 -
> > > drivers/staging/hikey9xx/Kconfig | 19 --
> > > drivers/staging/hikey9xx/Makefile | 3 -
> > > drivers/staging/hikey9xx/TODO | 5 -
> > > drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 316 ------------------
> > > .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 134 --------
> > > 12 files changed, 474 insertions(+), 480 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/Kconfig
> > > delete mode 100644 drivers/staging/hikey9xx/Makefile
> > > delete mode 100644 drivers/staging/hikey9xx/TODO
> > > delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> > > delete mode 100644 drivers/staging/hikey9xx/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..8e355cddd437
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> > > @@ -0,0 +1,134 @@
> > > +# 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 <[email protected]>
> > > +
> > > +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
> > > + Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
> > > +
> > > +properties:
> > > + $nodename:
> > > + pattern: "pmic@[0-9a-f]"
> > > +
> > > + compatible:
> > > + const: hisilicon,hi6421v600-spmi
> > > +
> > > + reg:
> > > + maxItems: 1
> > > +
> > > + '#interrupt-cells':
> > > + const: 2
> > > +
> > > + interrupt-controller: true
> > > +
> > > + gpios:
> > > + maxItems: 1
> > > + description: GPIO used for IRQs
> > > +
> > > + 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 9a69e3810964..89e84b050de6 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -8291,6 +8291,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 <[email protected]>
> > > +L: [email protected]
> > > +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 <[email protected]>
> > > S: Maintained
> > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > > index 5c7f2b100191..99b8da2548b5 100644
> > > --- a/drivers/mfd/Kconfig
> > > +++ b/drivers/mfd/Kconfig
> > > @@ -509,6 +509,22 @@ 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
> > > + select REGMAP_SPMI
> > > + 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 4f6d2b8a5f76..e87230fc61ac 100644
> > > --- a/drivers/mfd/Makefile
> > > +++ b/drivers/mfd/Makefile
> > > @@ -232,6 +232,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..2b7172560df7
> > > --- /dev/null
> > > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > > @@ -0,0 +1,316 @@
> > > +// 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
> >
> > Can this be updated?
>
> Do you mean updating the copyrights to cover this year? E.g.
> something like this:
>
> * Copyright (c) 2013-2021 Linaro Ltd.
> * Copyright (c) 2011-2021 Hisilicon.
> * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
>
> Right? Or are you meaning something else?
Yes, that's it. I know this is just a move, but to MFD, it's new.
> Btw, this device is a variant of the already-existing devices
> provided by the hi6421-pmic-core, which has:
>
> * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
> * http://www.hisilicon.com
> * Copyright (c) <2013-2017> Linaro Ltd.
> * https://www.linaro.org
> *
>
> The main difference is that this device is connected via a
> SPMI bus (there are other differences on register settings and
> LDO/BUCK regulators).
>
> >
> > > + */
> > > +
> > > +#include <linux/bitops.h>
> > > +#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>
> > > +
> > > +enum hi6421_spmi_pmic_irq_list {
> > > + OTMP = 0,
> > > + VBUS_CONNECT,
> > > + VBUS_DISCONNECT,
> > > + ALARMON_R,
> > > + HOLD_6S,
> > > + HOLD_1S,
> > > + POWERKEY_UP,
> > > + POWERKEY_DOWN,
> > > + OCP_SCP_R,
> > > + COUL_R,
> > > + SIM0_HPD_R,
> > > + SIM0_HPD_F,
> > > + SIM1_HPD_R,
> > > + SIM1_HPD_F,
> > > +
> > > + PMIC_IRQ_LIST_MAX
> > > +};
> > > +
> > > +#define HISI_IRQ_BANK_SIZE 2
> > > +
> > > +/*
> > > + * IRQ number for the power key button and mask for both UP and DOWN IRQs
> > > + */
> > > +#define HISI_POWERKEY_IRQ_NUM 0
> > > +#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
> > > +
> > > +/*
> > > + * Registers for IRQ address and IRQ mask bits
> > > + *
> > > + * Please notice that we need to regmap a larger region, as other
> > > + * registers are used by the regulators.
> > > + * See drivers/regulator/hi6421-regulator.c.
> > > + */
> > > +#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
> > > +#define SOC_PMIC_IRQ0_ADDR 0x0212
> > > +
> > > +/*
> > > + * The IRQs are mapped as:
> > > + *
> > > + * ====================== ============= ============ =====
> > > + * IRQ MASK REGISTER IRQ REGISTER BIT
> > > + * ====================== ============= ============ =====
> > > + * OTMP 0x0202 0x212 bit 0
> > > + * VBUS_CONNECT 0x0202 0x212 bit 1
> > > + * VBUS_DISCONNECT 0x0202 0x212 bit 2
> > > + * ALARMON_R 0x0202 0x212 bit 3
> > > + * HOLD_6S 0x0202 0x212 bit 4
> > > + * HOLD_1S 0x0202 0x212 bit 5
> > > + * POWERKEY_UP 0x0202 0x212 bit 6
> > > + * POWERKEY_DOWN 0x0202 0x212 bit 7
> > > + *
> > > + * OCP_SCP_R 0x0203 0x213 bit 0
> > > + * COUL_R 0x0203 0x213 bit 1
> > > + * SIM0_HPD_R 0x0203 0x213 bit 2
> > > + * SIM0_HPD_F 0x0203 0x213 bit 3
> > > + * SIM1_HPD_R 0x0203 0x213 bit 4
> > > + * SIM1_HPD_F 0x0203 0x213 bit 5
> > > + * ====================== ============= ============ =====
> > > + *
> > > + * Each mask register contains 8 bits. The ancillary macros below
> > > + * convert a number from 0 to 14 into a register address and a bit mask
> > > + */
> > > +#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
> > > + (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
> > > +#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
> > > +#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
> >
> > Are these lines up in real code? Looks like they're not in the diff.
>
> Weird. The changes to use those are at patch 3/8. All the above
> macros are used at the patch.
Sorry, that made no sense - it's been a long few days!
I meant to say "do these (the tabs) line up?"
> > > +static const struct mfd_cell hi6421v600_devs[] = {
> > > + { .name = "hi6421v600-regulator", },
> > > +};
> >
> > Where are the other devices?
>
> While this is a MFD device, as it has regulators, ADC and other
> stuff, right now, only the regulator and the IRQs are implemented.
>
> The IRQs are at the core of this driver, while the regulator
> is at the separate regulator driver.
The rule usually goes:
Drivers don't qualify as MFDs until you register >1 device.
[...]
> > > + for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
> > > + virq = irq_create_mapping(ddata->domain, i);
> > > + if (!virq) {
> > > + dev_err(dev, "Failed to map H/W IRQ\n");
> > > + return -ENOSPC;
> >
> > -ENOSPC doesn't seem right here.
> >
> > Can't find any other uses of it for irq_create_mapping() either.
>
> There are two drivers returning -ENOSPC:
>
> arch/powerpc/platforms/pseries/msi.c
> arch/powerpc/sysdev/mpic_u3msi.c
I only looked in drivers/
> But others return -EIO, -EINVAL, -ENOMEM, -ENODEV, -ENXIO.
>
> I think that -ENODEV would fit better here.
I think -ENXIO is the most common, followed by -EINVAL.
This doesn't have anything to do with devices per say.
> > > +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> > > +{
> > > + struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
> > > +
> > > + free_irq(ddata->irq, ddata);
> >
> > No devm_* version?
>
> Are there a devm_* variant for gpio_to_irq()?
Please refer to Dan's response.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
On Thu, Jun 24, 2021 at 03:08:00PM +0100, Lee Jones wrote:
> On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
>
> > Em Thu, 24 Jun 2021 12:33:28 +0100
> > Lee Jones <[email protected]> escreveu:
> > > > --- /dev/null
> > > > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > > > @@ -0,0 +1,316 @@
> > > > +// 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
> > >
> > > Can this be updated?
> >
> > Do you mean updating the copyrights to cover this year? E.g.
> > something like this:
> >
> > * Copyright (c) 2013-2021 Linaro Ltd.
> > * Copyright (c) 2011-2021 Hisilicon.
> > * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
> >
> > Right? Or are you meaning something else?
>
> Yes, that's it. I know this is just a move, but to MFD, it's new.
That's not how copyright works. Unless Linaro and Hisilicon made
nontrivial changes every year from 2011/2013 to 2021 you should not
change those lines like this.
Johan
On Thu, 24 Jun 2021 11:01:10 +0200, Mauro Carvalho Chehab wrote:
> This driver is ready for mainstream. So, move it out of staging.
>
> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
> ---
> .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 134 ++++++++
> MAINTAINERS | 7 +
> drivers/mfd/Kconfig | 16 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/hi6421-spmi-pmic.c | 316 ++++++++++++++++++
> drivers/staging/Kconfig | 2 -
> drivers/staging/Makefile | 1 -
> drivers/staging/hikey9xx/Kconfig | 19 --
> drivers/staging/hikey9xx/Makefile | 3 -
> drivers/staging/hikey9xx/TODO | 5 -
> drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 316 ------------------
> .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 134 --------
> 12 files changed, 474 insertions(+), 480 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/Kconfig
> delete mode 100644 drivers/staging/hikey9xx/Makefile
> delete mode 100644 drivers/staging/hikey9xx/TODO
> delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c
> delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.example.dt.yaml:0:0: /example-0/pmic@0: failed to match any schema with compatible: ['hisilicon,hi6421-spmi']
\ndoc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/1496456
This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit.
Em Thu, 24 Jun 2021 15:08:00 +0100
Lee Jones <[email protected]> escreveu:
> > > > +/*
> > > > + * The IRQs are mapped as:
> > > > + *
> > > > + * ====================== ============= ============ =====
> > > > + * IRQ MASK REGISTER IRQ REGISTER BIT
> > > > + * ====================== ============= ============ =====
> > > > + * OTMP 0x0202 0x212 bit 0
> > > > + * VBUS_CONNECT 0x0202 0x212 bit 1
> > > > + * VBUS_DISCONNECT 0x0202 0x212 bit 2
> > > > + * ALARMON_R 0x0202 0x212 bit 3
> > > > + * HOLD_6S 0x0202 0x212 bit 4
> > > > + * HOLD_1S 0x0202 0x212 bit 5
> > > > + * POWERKEY_UP 0x0202 0x212 bit 6
> > > > + * POWERKEY_DOWN 0x0202 0x212 bit 7
> > > > + *
> > > > + * OCP_SCP_R 0x0203 0x213 bit 0
> > > > + * COUL_R 0x0203 0x213 bit 1
> > > > + * SIM0_HPD_R 0x0203 0x213 bit 2
> > > > + * SIM0_HPD_F 0x0203 0x213 bit 3
> > > > + * SIM1_HPD_R 0x0203 0x213 bit 4
> > > > + * SIM1_HPD_F 0x0203 0x213 bit 5
> > > > + * ====================== ============= ============ =====
> > > > + *
> > > > + * Each mask register contains 8 bits. The ancillary macros below
> > > > + * convert a number from 0 to 14 into a register address and a bit mask
> > > > + */
> > > > +#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
> > > > + (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
> > > > +#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
> > > > +#define HISI_8BITS_MASK GENMASK(BITS_PER_BYTE - 1, 0)
> > >
> > > Are these lines up in real code? Looks like they're not in the diff.
> >
> > Weird. The changes to use those are at patch 3/8. All the above
> > macros are used at the patch.
>
> Sorry, that made no sense - it's been a long few days!
>
> I meant to say "do these (the tabs) line up?"
Yes, they line up (and aligned with the parenthesis, in the case of
HISI_IRQ_MASK_REG).
> > > > +static const struct mfd_cell hi6421v600_devs[] = {
> > > > + { .name = "hi6421v600-regulator", },
> > > > +};
> > >
> > > Where are the other devices?
> >
> > While this is a MFD device, as it has regulators, ADC and other
> > stuff, right now, only the regulator and the IRQs are implemented.
> >
> > The IRQs are at the core of this driver, while the regulator
> > is at the separate regulator driver.
>
> The rule usually goes:
>
> Drivers don't qualify as MFDs until you register >1 device.
Do you mean that, in order for this to be accepted, should
I move the irq code to a separate driver?
> > > > + for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
> > > > + virq = irq_create_mapping(ddata->domain, i);
> > > > + if (!virq) {
> > > > + dev_err(dev, "Failed to map H/W IRQ\n");
> > > > + return -ENOSPC;
> > >
> > > -ENOSPC doesn't seem right here.
> > >
> > > Can't find any other uses of it for irq_create_mapping() either.
> >
> > There are two drivers returning -ENOSPC:
> >
> > arch/powerpc/platforms/pseries/msi.c
> > arch/powerpc/sysdev/mpic_u3msi.c
>
> I only looked in drivers/
>
> > But others return -EIO, -EINVAL, -ENOMEM, -ENODEV, -ENXIO.
> >
> > I think that -ENODEV would fit better here.
>
> I think -ENXIO is the most common, followed by -EINVAL.
>
> This doesn't have anything to do with devices per say.
Ok. I'll change it to -ENXIO.
> > > > +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev)
> > > > +{
> > > > + struct hi6421_spmi_pmic *ddata = dev_get_drvdata(&pdev->dev);
> > > > +
> > > > + free_irq(ddata->irq, ddata);
> > >
> > > No devm_* version?
> >
> > Are there a devm_* variant for gpio_to_irq()?
>
> Please refer to Dan's response.
Ok.
Thanks,
Mauro
Em Thu, 24 Jun 2021 16:26:00 +0200
Johan Hovold <[email protected]> escreveu:
> On Thu, Jun 24, 2021 at 03:08:00PM +0100, Lee Jones wrote:
> > On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> >
> > > Em Thu, 24 Jun 2021 12:33:28 +0100
> > > Lee Jones <[email protected]> escreveu:
>
> > > > > --- /dev/null
> > > > > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > > > > @@ -0,0 +1,316 @@
> > > > > +// 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
> > > >
> > > > Can this be updated?
> > >
> > > Do you mean updating the copyrights to cover this year? E.g.
> > > something like this:
> > >
> > > * Copyright (c) 2013-2021 Linaro Ltd.
> > > * Copyright (c) 2011-2021 Hisilicon.
> > > * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
> > >
> > > Right? Or are you meaning something else?
> >
> > Yes, that's it. I know this is just a move, but to MFD, it's new.
>
> That's not how copyright works. Unless Linaro and Hisilicon made
> nontrivial changes every year from 2011/2013 to 2021 you should not
> change those lines like this.
Only Linaro can answer what happened up to 2018, as this driver
originally came from a Linaro tree, which has exactly one commit
for this driver:
https://github.com/96boards-hikey/linux/commit/08464419fba2417aa849fce976fac9c5f51b3ada#diff-604ef8563dcd9ace6e3e58aac38337c72924b0889f6972d7ee9e15e2335ba964
After merged upstream at staging, all changes are covered by the
Huawei's copyright (2020-2021).
So, I'll just drop this patch. If the information is not accurate,
someone from the original copyright holders can send followup
patches.
Thanks,
Mauro
On Thu, 24 Jun 2021, Johan Hovold wrote:
> On Thu, Jun 24, 2021 at 03:08:00PM +0100, Lee Jones wrote:
> > On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> >
> > > Em Thu, 24 Jun 2021 12:33:28 +0100
> > > Lee Jones <[email protected]> escreveu:
>
> > > > > --- /dev/null
> > > > > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > > > > @@ -0,0 +1,316 @@
> > > > > +// 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
> > > >
> > > > Can this be updated?
> > >
> > > Do you mean updating the copyrights to cover this year? E.g.
> > > something like this:
> > >
> > > * Copyright (c) 2013-2021 Linaro Ltd.
> > > * Copyright (c) 2011-2021 Hisilicon.
> > > * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
> > >
> > > Right? Or are you meaning something else?
> >
> > Yes, that's it. I know this is just a move, but to MFD, it's new.
>
> That's not how copyright works. Unless Linaro and Hisilicon made
> nontrivial changes every year from 2011/2013 to 2021 you should not
> change those lines like this.
Thanks for the pointer. After receiving these, I went and did some
reading-up on the subject, and you're quite right in what you say.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog
On Fri, 25 Jun 2021, Mauro Carvalho Chehab wrote:
> Em Thu, 24 Jun 2021 16:26:00 +0200
> Johan Hovold <[email protected]> escreveu:
>
> > On Thu, Jun 24, 2021 at 03:08:00PM +0100, Lee Jones wrote:
> > > On Thu, 24 Jun 2021, Mauro Carvalho Chehab wrote:
> > >
> > > > Em Thu, 24 Jun 2021 12:33:28 +0100
> > > > Lee Jones <[email protected]> escreveu:
> >
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/mfd/hi6421-spmi-pmic.c
> > > > > > @@ -0,0 +1,316 @@
> > > > > > +// 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
> > > > >
> > > > > Can this be updated?
> > > >
> > > > Do you mean updating the copyrights to cover this year? E.g.
> > > > something like this:
> > > >
> > > > * Copyright (c) 2013-2021 Linaro Ltd.
> > > > * Copyright (c) 2011-2021 Hisilicon.
> > > > * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
> > > >
> > > > Right? Or are you meaning something else?
> > >
> > > Yes, that's it. I know this is just a move, but to MFD, it's new.
> >
> > That's not how copyright works. Unless Linaro and Hisilicon made
> > nontrivial changes every year from 2011/2013 to 2021 you should not
> > change those lines like this.
>
> Only Linaro can answer what happened up to 2018, as this driver
> originally came from a Linaro tree, which has exactly one commit
> for this driver:
>
> https://github.com/96boards-hikey/linux/commit/08464419fba2417aa849fce976fac9c5f51b3ada#diff-604ef8563dcd9ace6e3e58aac38337c72924b0889f6972d7ee9e15e2335ba964
>
> After merged upstream at staging, all changes are covered by the
> Huawei's copyright (2020-2021).
>
> So, I'll just drop this patch. If the information is not accurate,
> someone from the original copyright holders can send followup
> patches.
After taking the time to read up on Copyright rules and expectations,
I think we can pretty much safely say that all of the Copyright
entries above are incorrect.
Copyright dates should only be listed if significant works were
undertaken in each of the years listed. So unless large adaptions
happened every year since 2011, which I doubt very much, they're
wrong.
--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog