diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 23:13:35 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 23:13:35 +0100 |
| commit | ec3703d2063724aea40e3c87daf05547c1e8a814 (patch) | |
| tree | a421546fde3f2596b65a59ed874dffc091a80310 /drivers | |
| parent | 4292a3be62d61e6ddbe2944ae0c04c75283dba34 (diff) | |
| parent | 3443eec9c55d128064c83225a9111f1a1a37277a (diff) | |
| download | linux-next-history-ec3703d2063724aea40e3c87daf05547c1e8a814.tar.gz | |
Merge branch 'spmi-next' of https://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/spmi/spmi-pmic-arb.c | 142 | ||||
| -rw-r--r-- | drivers/spmi/spmi.c | 4 |
2 files changed, 114 insertions, 32 deletions
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 69f8d456324a4..2e2cb47741038 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -28,6 +28,7 @@ #define PMIC_ARB_VERSION_V5_MIN 0x50000000 #define PMIC_ARB_VERSION_V7_MIN 0x70000000 #define PMIC_ARB_VERSION_V8_MIN 0x80000000 +#define PMIC_ARB_VERSION_V8P5_MIN 0x80050000 #define PMIC_ARB_INT_EN 0x0004 #define PMIC_ARB_FEATURES 0x0004 @@ -62,14 +63,6 @@ /* Ownership Table */ #define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7) -/* Channel Status fields */ -enum pmic_arb_chnl_status { - PMIC_ARB_STATUS_DONE = BIT(0), - PMIC_ARB_STATUS_FAILURE = BIT(1), - PMIC_ARB_STATUS_DENIED = BIT(2), - PMIC_ARB_STATUS_DROPPED = BIT(3), -}; - /* Command register fields */ #define PMIC_ARB_CMD_MAX_BYTE_COUNT 8 @@ -239,6 +232,7 @@ struct spmi_pmic_arb { * on v2 address of SPMI_PIC_IRQ_CLEARn. * @apid_map_offset: offset of PMIC_ARB_REG_CHNLn * @apid_owner: on v2 and later address of SPMI_PERIPHn_2OWNER_TABLE_REG + * @check_chnl_status: checks channel status and returns error code if any */ struct pmic_arb_ver_ops { const char *ver_str; @@ -261,6 +255,8 @@ struct pmic_arb_ver_ops { void __iomem *(*irq_clear)(struct spmi_pmic_arb_bus *bus, u16 n); u32 (*apid_map_offset)(u16 n); void __iomem *(*apid_owner)(struct spmi_pmic_arb_bus *bus, u16 n); + int (*check_chnl_status)(struct spmi_controller *ctrl, u32 status, + u8 sid, u16 addr, u32 offset); }; static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, @@ -306,6 +302,84 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, __raw_writel(data, pmic_arb->wr_base + reg); } +static int pmic_arb_check_chnl_status_v1(struct spmi_controller *ctrl, + u32 status, u8 sid, u16 addr, + u32 offset) +{ + /* Check if DONE bit is set */ + if (!(status & BIT(0))) + return -EAGAIN; + + if (status & BIT(1)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n", + __func__, sid, addr, status, offset); + WARN_ON(1); + return -EIO; + } + + if (status & BIT(2)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n", + __func__, sid, addr, status); + return -EPERM; + } + + if (status & BIT(3)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n", + __func__, sid, addr, status); + return -EIO; + } + + return 0; +} + +static int pmic_arb_check_chnl_status_v8p5(struct spmi_controller *ctrl, + u32 status, u8 sid, u16 addr, + u32 offset) +{ + /* Check if DONE bit is set */ + if (!(status & BIT(0))) + return -EAGAIN; + + if (status & BIT(1)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n", + __func__, sid, addr, status, offset); + WARN_ON(1); + return -EIO; + } + + if (status & BIT(2)) { + dev_err(&ctrl->dev, "%s: %#x %#x: CRC error (%#x)\n", + __func__, sid, addr, status); + return -EIO; + } + + if (status & BIT(3)) { + dev_err(&ctrl->dev, "%s: %#x %#x: parity error (%#x)\n", + __func__, sid, addr, status); + return -EIO; + } + + if (status & BIT(4)) { + dev_err(&ctrl->dev, "%s: %#x %#x: NACK error (%#x)\n", + __func__, sid, addr, status); + return -EIO; + } + + if (status & BIT(5)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n", + __func__, sid, addr, status); + return -EPERM; + } + + if (status & BIT(6)) { + dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n", + __func__, sid, addr, status); + return -EIO; + } + + return 0; +} + static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, void __iomem *base, u8 sid, u16 addr, enum pmic_arb_channel ch_type) @@ -327,28 +401,10 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, while (timeout--) { status = readl_relaxed(base + offset); - if (status & PMIC_ARB_STATUS_DONE) { - if (status & PMIC_ARB_STATUS_DENIED) { - dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n", - __func__, sid, addr, status); - return -EPERM; - } + rc = pmic_arb->ver_ops->check_chnl_status(ctrl, status, sid, addr, offset); + if (rc != -EAGAIN) + return rc; - if (status & PMIC_ARB_STATUS_FAILURE) { - dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n", - __func__, sid, addr, status, offset); - WARN_ON(1); - return -EIO; - } - - if (status & PMIC_ARB_STATUS_DROPPED) { - dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n", - __func__, sid, addr, status); - return -EIO; - } - - return 0; - } udelay(1); } @@ -1768,6 +1824,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = { .irq_clear = pmic_arb_irq_clear_v1, .apid_map_offset = pmic_arb_apid_map_offset_v2, .apid_owner = pmic_arb_apid_owner_v2, + .check_chnl_status = pmic_arb_check_chnl_status_v1, }; static const struct pmic_arb_ver_ops pmic_arb_v2 = { @@ -1784,6 +1841,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = { .irq_clear = pmic_arb_irq_clear_v2, .apid_map_offset = pmic_arb_apid_map_offset_v2, .apid_owner = pmic_arb_apid_owner_v2, + .check_chnl_status = pmic_arb_check_chnl_status_v1, }; static const struct pmic_arb_ver_ops pmic_arb_v3 = { @@ -1800,6 +1858,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = { .irq_clear = pmic_arb_irq_clear_v2, .apid_map_offset = pmic_arb_apid_map_offset_v2, .apid_owner = pmic_arb_apid_owner_v2, + .check_chnl_status = pmic_arb_check_chnl_status_v1, }; static const struct pmic_arb_ver_ops pmic_arb_v5 = { @@ -1816,6 +1875,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = { .irq_clear = pmic_arb_irq_clear_v5, .apid_map_offset = pmic_arb_apid_map_offset_v5, .apid_owner = pmic_arb_apid_owner_v2, + .check_chnl_status = pmic_arb_check_chnl_status_v1, }; static const struct pmic_arb_ver_ops pmic_arb_v7 = { @@ -1832,6 +1892,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v7 = { .irq_clear = pmic_arb_irq_clear_v7, .apid_map_offset = pmic_arb_apid_map_offset_v7, .apid_owner = pmic_arb_apid_owner_v7, + .check_chnl_status = pmic_arb_check_chnl_status_v1, }; static const struct pmic_arb_ver_ops pmic_arb_v8 = { @@ -1849,6 +1910,25 @@ static const struct pmic_arb_ver_ops pmic_arb_v8 = { .irq_clear = pmic_arb_irq_clear_v8, .apid_map_offset = pmic_arb_apid_map_offset_v8, .apid_owner = pmic_arb_apid_owner_v8, + .check_chnl_status = pmic_arb_check_chnl_status_v1, +}; + +static const struct pmic_arb_ver_ops pmic_arb_v8p5 = { + .ver_str = "v8.5", + .get_core_resources = pmic_arb_get_core_resources_v8, + .get_bus_resources = pmic_arb_get_bus_resources_v8, + .init_apid = pmic_arb_init_apid_v8, + .ppid_to_apid = pmic_arb_ppid_to_apid_v5, + .non_data_cmd = pmic_arb_non_data_cmd_v2, + .offset = pmic_arb_offset_v8, + .fmt_cmd = pmic_arb_fmt_cmd_v2, + .owner_acc_status = pmic_arb_owner_acc_status_v7, + .acc_enable = pmic_arb_acc_enable_v8, + .irq_status = pmic_arb_irq_status_v8, + .irq_clear = pmic_arb_irq_clear_v8, + .apid_map_offset = pmic_arb_apid_map_offset_v8, + .apid_owner = pmic_arb_apid_owner_v8, + .check_chnl_status = pmic_arb_check_chnl_status_v8p5, }; static const struct irq_domain_ops pmic_arb_irq_domain_ops = { @@ -2030,8 +2110,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) pmic_arb->ver_ops = &pmic_arb_v5; else if (hw_ver < PMIC_ARB_VERSION_V8_MIN) pmic_arb->ver_ops = &pmic_arb_v7; - else + else if (hw_ver < PMIC_ARB_VERSION_V8P5_MIN) pmic_arb->ver_ops = &pmic_arb_v8; + else + pmic_arb->ver_ops = &pmic_arb_v8p5; err = pmic_arb->ver_ops->get_core_resources(pdev, core); if (err) diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c index e889b129f3ac3..57b7c0cb42407 100644 --- a/drivers/spmi/spmi.c +++ b/drivers/spmi/spmi.c @@ -450,7 +450,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent, if (WARN_ON(!parent)) return ERR_PTR(-EINVAL); - ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL); + ctrl = kzalloc_flex(*ctrl, priv, size); if (!ctrl) return ERR_PTR(-ENOMEM); @@ -459,7 +459,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent, ctrl->dev.bus = &spmi_bus_type; ctrl->dev.parent = parent; ctrl->dev.of_node = parent->of_node; - spmi_controller_set_drvdata(ctrl, &ctrl[1]); + spmi_controller_set_drvdata(ctrl, ctrl->priv); id = ida_alloc(&ctrl_ida, GFP_KERNEL); if (id < 0) { |
