From eeeec6c5475e914157feab00bdcaed79132e47a2 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 9 Apr 2025 17:03:57 +0300 Subject: [PATCH 01/11] i3c: mipi-i3c-hci: Allow only relevant INTR_STATUS bit updates Since MIPI I3C HCI specification version v0.8 INTR_STATUS bits 9:0 are reserved. Version v0.5 has bits 9 and 5:0 in use but not handled by the current driver code and not needed in DMA transfers. PIO transfers with v0.5 would require changes to both core.c: i3c_hci_irq_handler() and pio.c: hci_pio_irq_handler() though. For these reasons don't enable signal updates from INTR_STATUS bits 9:0. It allow to get rid of "unexpected INTR_STATUS" error messages on old v0.5 IP version and is a no-op for later versions starting from v0.8. Signed-off-by: Jarkko Nikula Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250409140401.299251-1-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index a71226d7ca59..ba7aa6bbcec5 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -699,9 +699,14 @@ static int i3c_hci_init(struct i3c_hci *hci) if (ret) return -ENXIO; - /* Disable all interrupts and allow all signal updates */ + /* Disable all interrupts */ reg_write(INTR_SIGNAL_ENABLE, 0x0); - reg_write(INTR_STATUS_ENABLE, 0xffffffff); + /* + * Only allow bit 31:10 signal updates because + * Bit 0:9 are reserved in IP version >= 0.8 + * Bit 0:5 are defined in IP version < 0.8 but not handled by PIO code + */ + reg_write(INTR_STATUS_ENABLE, GENMASK(31, 10)); /* Make sure our data ordering fits the host's */ regval = reg_read(HC_CONTROL); From 279c24021b838e76ca8441e9446e0ab45271153a Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 9 Apr 2025 17:03:58 +0300 Subject: [PATCH 02/11] i3c: mipi-i3c-hci: Fix handling status of i3c_hci_irq_handler() Return IRQ_HANDLED from the i3c_hci_irq_handler() only if some INTR_STATUS bit was set or if DMA/PIO handler handled it. Currently it returns IRQ_HANDLED in case INTR_STATUS is zero and IO handler returns false. Which could be the case if interrupt comes from other device or is spurious. Reviewed-by: Frank Li Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20250409140401.299251-2-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index ba7aa6bbcec5..780e9db7e21e 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -594,6 +594,7 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) if (val) { reg_write(INTR_STATUS, val); + result = IRQ_HANDLED; } if (val & INTR_HC_RESET_CANCEL) { @@ -605,12 +606,11 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) val &= ~INTR_HC_INTERNAL_ERR; } - hci->io->irq_handler(hci); + if (hci->io->irq_handler(hci)) + result = IRQ_HANDLED; if (val) dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val); - else - result = IRQ_HANDLED; return result; } From a7035a8ee96648bfbd2cd747308bca41122500ab Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 9 Apr 2025 17:03:59 +0300 Subject: [PATCH 03/11] i3c: mipi-i3c-hci: Clear INTR_STATUS unconditionally Status fields in INTR_STATUS register are write 1 to clear so do it unconditionally and move clearing of them out of an if block. Suggested-by: Frank Li Signed-off-by: Jarkko Nikula Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250409140401.299251-3-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 780e9db7e21e..4c4100d2d9af 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -590,12 +590,11 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) u32 val; val = reg_read(INTR_STATUS); + reg_write(INTR_STATUS, val); DBG("INTR_STATUS = %#x", val); - if (val) { - reg_write(INTR_STATUS, val); + if (val) result = IRQ_HANDLED; - } if (val & INTR_HC_RESET_CANCEL) { DBG("cancelled reset"); From 7479d2675c50a53ff802fad2e8176f830e342bb1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 9 Apr 2025 17:04:00 +0300 Subject: [PATCH 04/11] i3c: mipi-i3c-hci: Change name of INTR_STATUS bit 11 INTR_STATUS bit 11 INTR_HC_RESET_CANCEL was probably projected for the MIPI I3C HCI specification version 2 but was not ever implemented. This bit is first time specified in the v1.2 as HC_SEQ_CANCEL_STAT "Host Controller Cancelled Transaction Sequence". Update the definition and debug print of it accordingly. While at it, change DBG() print to dev_dbg(). Reviewed-by: Frank Li Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20250409140401.299251-4-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 4c4100d2d9af..0bb74173ca94 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -78,7 +78,7 @@ #define INTR_SIGNAL_ENABLE 0x28 #define INTR_FORCE 0x2c #define INTR_HC_CMD_SEQ_UFLOW_STAT BIT(12) /* Cmd Sequence Underflow */ -#define INTR_HC_RESET_CANCEL BIT(11) /* HC Cancelled Reset */ +#define INTR_HC_SEQ_CANCEL BIT(11) /* HC Cancelled Transaction Sequence */ #define INTR_HC_INTERNAL_ERR BIT(10) /* HC Internal Error */ #define DAT_SECTION 0x30 /* Device Address Table */ @@ -596,9 +596,10 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) if (val) result = IRQ_HANDLED; - if (val & INTR_HC_RESET_CANCEL) { - DBG("cancelled reset"); - val &= ~INTR_HC_RESET_CANCEL; + if (val & INTR_HC_SEQ_CANCEL) { + dev_dbg(&hci->master.dev, + "Host Controller Cancelled Transaction Sequence\n"); + val &= ~INTR_HC_SEQ_CANCEL; } if (val & INTR_HC_INTERNAL_ERR) { dev_err(&hci->master.dev, "Host Controller Internal Error\n"); From bd916806632d1a22a10a30d5ab7cce549791a563 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 9 Apr 2025 17:04:01 +0300 Subject: [PATCH 05/11] i3c: mipi-i3c-hci: Move unexpected INTR_STATUS print before IO handler Move "unexpected INTR_STATUS" error print before calling the IO handler as it is more consistent that way. Otherwise it may be confusing if generic interrupt related prints are mixed with IO handler prints. Since this error print is more indication of missing code rather than runtime error downgrade it to dev_warn_once(). Reviewed-by: Frank Li Signed-off-by: Jarkko Nikula Link: https://lore.kernel.org/r/20250409140401.299251-5-jarkko.nikula@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 0bb74173ca94..bc4538694540 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -606,12 +606,13 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) val &= ~INTR_HC_INTERNAL_ERR; } + if (val) + dev_warn_once(&hci->master.dev, + "unexpected INTR_STATUS %#x\n", val); + if (hci->io->irq_handler(hci)) result = IRQ_HANDLED; - if (val) - dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val); - return result; } From 8d29fa6d921ca4f9f63f73598833e53ece1d3b4e Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Tue, 15 Apr 2025 13:18:07 +0800 Subject: [PATCH 06/11] i3c: master: svc: Receive IBI requests in interrupt context Moving the job from workqueue to ISR for two reasons. 1. Improve bus utilization. If the requests are postponed to be received in the workqueue thread, the SDA line remains low for a long time while the system loading is high. During this period, the bus is not available for other targets to raise requests. 2. Ensure prompt response to requests. For timing-critical requests, the target may encouter a failure or the event is missed if the request is not received in time. IBI request is short, ISR can receive the data quickly and then queue a work to handle it in the bottom half. Signed-off-by: Stanley Chu Reviewed-by: Frank Li Acked-by: Miquel Raynal Link: https://lore.kernel.org/r/20250415051808.88091-2-yschu@nuvoton.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/svc-i3c-master.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 85e16de208d3..7ceaf3ec45bb 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -201,7 +201,6 @@ struct svc_i3c_drvdata { * @addrs: Array containing the dynamic addresses of each attached device * @descs: Array of descriptors, one per attached device * @hj_work: Hot-join work - * @ibi_work: IBI work * @irq: Main interrupt * @pclk: System clock * @fclk: Fast clock (bus) @@ -229,7 +228,6 @@ struct svc_i3c_master { u8 addrs[SVC_I3C_MAX_DEVS]; struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS]; struct work_struct hj_work; - struct work_struct ibi_work; int irq; struct clk *pclk; struct clk *fclk; @@ -487,9 +485,8 @@ static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 msta return ret; } -static void svc_i3c_master_ibi_work(struct work_struct *work) +static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master) { - struct svc_i3c_master *master = container_of(work, struct svc_i3c_master, ibi_work); struct svc_i3c_i2c_dev_data *data; unsigned int ibitype, ibiaddr; struct i3c_dev_desc *dev; @@ -504,7 +501,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) * schedule during the whole I3C transaction, otherwise, the I3C bus timeout may happen if * any irq or schedule happen during transaction. */ - guard(spinlock_irqsave)(&master->xferqueue.lock); + guard(spinlock)(&master->xferqueue.lock); /* * IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing @@ -530,7 +527,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) if (ret) { dev_err(master->dev, "Timeout when polling for IBIWON\n"); svc_i3c_master_emit_stop(master); - goto reenable_ibis; + return; } status = readl(master->regs + SVC_I3C_MSTATUS); @@ -574,7 +571,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) svc_i3c_master_emit_stop(master); - goto reenable_ibis; + return; } /* Handle the non critical tasks */ @@ -597,9 +594,6 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) default: break; } - -reenable_ibis: - svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); } static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) @@ -618,10 +612,12 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) !SVC_I3C_MSTATUS_STATE_SLVREQ(active)) return IRQ_HANDLED; - svc_i3c_master_disable_interrupts(master); - - /* Handle the interrupt in a non atomic context */ - queue_work(master->base.wq, &master->ibi_work); + /* + * The SDA line remains low until the request is processed. + * Receive the request in the interrupt context to respond promptly + * and restore the bus to idle state. + */ + svc_i3c_master_ibi_isr(master); return IRQ_HANDLED; } @@ -1947,7 +1943,6 @@ static int svc_i3c_master_probe(struct platform_device *pdev) return ret; INIT_WORK(&master->hj_work, svc_i3c_master_hj_work); - INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_work); mutex_init(&master->lock); ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler, From 81f2a9af982120104d5e9211b15f3a83281972c1 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Tue, 15 Apr 2025 13:18:08 +0800 Subject: [PATCH 07/11] i3c: master: svc: Emit STOP asap in the IBI transaction Queuing the IBI request does not need to be done earlier than emitting the STOP. Emitting STOP immediately after receiving the IBI request can complete the IBI transaction earlier and return the bus to idle. Signed-off-by: Stanley Chu Reviewed-by: Frank Li Acked-by: Miquel Raynal Link: https://lore.kernel.org/r/20250415051808.88091-3-yschu@nuvoton.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/svc-i3c-master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 7ceaf3ec45bb..9b23239ad8db 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -577,11 +577,11 @@ static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master) /* Handle the non critical tasks */ switch (ibitype) { case SVC_I3C_MSTATUS_IBITYPE_IBI: + svc_i3c_master_emit_stop(master); if (dev) { i3c_master_queue_ibi(dev, master->ibi.tbq_slot); master->ibi.tbq_slot = NULL; } - svc_i3c_master_emit_stop(master); break; case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: svc_i3c_master_emit_stop(master); From 12cbd157344848b1bd726ecadce27532d79b785a Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 29 Apr 2025 01:42:34 -0400 Subject: [PATCH 08/11] i3c: master: svc: skip address resend on repeat START According to the I3C specification, address arbitration only happens during the START. Repeated START do not initiate arbitration, and In-Band Interrupts (IBIs) cannot occur at this stage. Resending the address upon a NACK in a repeat START is therefore redundant and unnecessary. Avoid redundant retries, improving efficiency and ensuring protocol compliance. Signed-off-by: Frank Li Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20250429054234.4013929-1-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/svc-i3c-master.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 9b23239ad8db..279268a180e1 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -1277,9 +1277,9 @@ static int svc_i3c_master_write(struct svc_i3c_master *master, static int svc_i3c_master_xfer(struct svc_i3c_master *master, bool rnw, unsigned int xfer_type, u8 addr, u8 *in, const u8 *out, unsigned int xfer_len, - unsigned int *actual_len, bool continued) + unsigned int *actual_len, bool continued, bool repeat_start) { - int retry = 2; + int retry = repeat_start ? 1 : 2; u32 reg; int ret; @@ -1464,7 +1464,7 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master) ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type, cmd->addr, cmd->in, cmd->out, cmd->len, &cmd->actual_len, - cmd->continued); + cmd->continued, i > 0); /* cmd->xfer is NULL if I2C or CCC transfer */ if (cmd->xfer) cmd->xfer->actual_len = cmd->actual_len; From 489c773a68de187ad11482433119811949fbb88d Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Sun, 27 Apr 2025 16:32:28 +0800 Subject: [PATCH 09/11] dt-bindings: i3c: silvaco,i3c-master: add i.MX94 and i.MX95 I3C Add compatible string "nxp,imx94-i3c" and "nxp,imx95-i3c" for the i.MX94 chip and i.MX95 chip. Backward is compatible with "silvaco,i3c-master-v1". Also i.MX94 and i.MX95 I3C only need two clocks and Legacy I3C needs three clocks. So add restrictions for clock and clock-names properties for different Socs. Signed-off-by: Carlos Song Reviewed-by: Frank Li Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250427083230.3325700-2-carlos.song@nxp.com Signed-off-by: Alexandre Belloni --- .../bindings/i3c/silvaco,i3c-master.yaml | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml index 4fbdcdac0aee..853092f7522d 100644 --- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml @@ -9,14 +9,17 @@ title: Silvaco I3C master maintainers: - Conor Culhane -allOf: - - $ref: i3c.yaml# - properties: compatible: - enum: - - nuvoton,npcm845-i3c - - silvaco,i3c-master-v1 + oneOf: + - enum: + - nuvoton,npcm845-i3c + - silvaco,i3c-master-v1 + - items: + - enum: + - nxp,imx94-i3c + - nxp,imx95-i3c + - const: silvaco,i3c-master-v1 reg: maxItems: 1 @@ -25,12 +28,14 @@ properties: maxItems: 1 clocks: + minItems: 2 items: - description: system clock - description: bus clock - description: other (slower) events clock clock-names: + minItems: 2 items: - const: pclk - const: fast_clk @@ -46,6 +51,34 @@ required: - clock-names - clocks +allOf: + - $ref: i3c.yaml# + - if: + properties: + compatible: + enum: + - nuvoton,npcm845-i3c + - silvaco,i3c-master-v1 + then: + properties: + clocks: + minItems: 3 + clock-names: + minItems: 3 + - if: + properties: + compatible: + contains: + enum: + - nxp,imx94-i3c + - nxp,imx95-i3c + then: + properties: + clocks: + maxItems: 2 + clock-names: + maxItems: 2 + unevaluatedProperties: false examples: From cd1a6a0c69e75bf64b44b00186136e563f392b50 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Sun, 27 Apr 2025 16:32:29 +0800 Subject: [PATCH 10/11] i3c: master: svc: switch to bulk clk API for flexible clock support Use the clk_bulk API to handle clocks, so the code can support different numbers of clocks more easily. Make the code cleaner and more flexible. No change in functionality. Signed-off-by: Carlos Song Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250427083230.3325700-3-carlos.song@nxp.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/svc-i3c-master.c | 76 ++++++++++------------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 279268a180e1..7e1a7cb94b43 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -202,9 +202,9 @@ struct svc_i3c_drvdata { * @descs: Array of descriptors, one per attached device * @hj_work: Hot-join work * @irq: Main interrupt - * @pclk: System clock + * @num_clks: I3C clock number * @fclk: Fast clock (bus) - * @sclk: Slow clock (other events) + * @clks: I3C clock array * @xferqueue: Transfer queue structure * @xferqueue.list: List member * @xferqueue.cur: Current ongoing transfer @@ -229,9 +229,9 @@ struct svc_i3c_master { struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS]; struct work_struct hj_work; int irq; - struct clk *pclk; + int num_clks; struct clk *fclk; - struct clk *sclk; + struct clk_bulk_data *clks; struct { struct list_head list; struct svc_i3c_xfer *cur; @@ -1871,42 +1871,11 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = { .set_speed = svc_i3c_master_set_speed, }; -static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master) -{ - int ret = 0; - - ret = clk_prepare_enable(master->pclk); - if (ret) - return ret; - - ret = clk_prepare_enable(master->fclk); - if (ret) { - clk_disable_unprepare(master->pclk); - return ret; - } - - ret = clk_prepare_enable(master->sclk); - if (ret) { - clk_disable_unprepare(master->pclk); - clk_disable_unprepare(master->fclk); - return ret; - } - - return 0; -} - -static void svc_i3c_master_unprepare_clks(struct svc_i3c_master *master) -{ - clk_disable_unprepare(master->pclk); - clk_disable_unprepare(master->fclk); - clk_disable_unprepare(master->sclk); -} - static int svc_i3c_master_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct svc_i3c_master *master; - int ret; + int ret, i; master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL); if (!master) @@ -1920,27 +1889,31 @@ static int svc_i3c_master_probe(struct platform_device *pdev) if (IS_ERR(master->regs)) return PTR_ERR(master->regs); - master->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(master->pclk)) - return PTR_ERR(master->pclk); + master->num_clks = devm_clk_bulk_get_all(dev, &master->clks); + if (master->num_clks < 0) + return dev_err_probe(dev, -EINVAL, "can't get I3C clocks\n"); - master->fclk = devm_clk_get(dev, "fast_clk"); + for (i = 0; i < master->num_clks; i++) { + if (!strcmp(master->clks[i].id, "fast_clk")) + break; + } + + if (i == master->num_clks) + return dev_err_probe(dev, -EINVAL, + "can't get I3C peripheral clock\n"); + + master->fclk = master->clks[i].clk; if (IS_ERR(master->fclk)) return PTR_ERR(master->fclk); - master->sclk = devm_clk_get(dev, "slow_clk"); - if (IS_ERR(master->sclk)) - return PTR_ERR(master->sclk); - master->irq = platform_get_irq(pdev, 0); if (master->irq < 0) return master->irq; master->dev = dev; - - ret = svc_i3c_master_prepare_clks(master); + ret = clk_bulk_prepare_enable(master->num_clks, master->clks); if (ret) - return ret; + return dev_err_probe(dev, ret, "can't enable I3C clocks\n"); INIT_WORK(&master->hj_work, svc_i3c_master_hj_work); mutex_init(&master->lock); @@ -1993,7 +1966,7 @@ static int svc_i3c_master_probe(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); err_disable_clks: - svc_i3c_master_unprepare_clks(master); + clk_bulk_disable_unprepare(master->num_clks, master->clks); return ret; } @@ -2031,7 +2004,7 @@ static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) struct svc_i3c_master *master = dev_get_drvdata(dev); svc_i3c_save_regs(master); - svc_i3c_master_unprepare_clks(master); + clk_bulk_disable_unprepare(master->num_clks, master->clks); pinctrl_pm_select_sleep_state(dev); return 0; @@ -2040,9 +2013,12 @@ static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) static int __maybe_unused svc_i3c_runtime_resume(struct device *dev) { struct svc_i3c_master *master = dev_get_drvdata(dev); + int ret; pinctrl_pm_select_default_state(dev); - svc_i3c_master_prepare_clks(master); + ret = clk_bulk_prepare_enable(master->num_clks, master->clks); + if (ret) + return ret; svc_i3c_restore_regs(master); From 00286d7d643d3c98e48d9cc3a9f471b37154f462 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 6 May 2025 09:52:11 +0200 Subject: [PATCH 11/11] i3c: controllers do not need to depend on I3C The Kconfig file for controller drivers is only sourced if the I3C symbol is enabled. No need to check for that in individual drivers. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20250506075247.1545-2-wsa+renesas@sang-engineering.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig index 77da199c7413..7b30db3253af 100644 --- a/drivers/i3c/master/Kconfig +++ b/drivers/i3c/master/Kconfig @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config CDNS_I3C_MASTER tristate "Cadence I3C master driver" - depends on I3C depends on HAS_IOMEM depends on !(ALPHA || PARISC) help @@ -9,7 +8,6 @@ config CDNS_I3C_MASTER config DW_I3C_MASTER tristate "Synospsys DesignWare I3C master driver" - depends on I3C depends on HAS_IOMEM depends on !(ALPHA || PARISC) # ALPHA and PARISC needs {read,write}sl() @@ -38,7 +36,6 @@ config AST2600_I3C_MASTER config SVC_I3C_MASTER tristate "Silvaco I3C Dual-Role Master driver" - depends on I3C depends on HAS_IOMEM depends on !(ALPHA || PARISC) help @@ -46,7 +43,6 @@ config SVC_I3C_MASTER config MIPI_I3C_HCI tristate "MIPI I3C Host Controller Interface driver (EXPERIMENTAL)" - depends on I3C depends on HAS_IOMEM help Support for hardware following the MIPI Aliance's I3C Host Controller