diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-01 16:47:47 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-01 16:47:47 -0700 |
commit | 1df7752800b41de14dd268bf53d854bc81017973 (patch) | |
tree | 032902d3799e7ce55fca8a64269ba6fa462fa069 | |
parent | 696c45bcc3c35486578fd741d8551865aee42915 (diff) | |
parent | bd496a44f041da9ef3afe14d1d6193d460424e91 (diff) |
Merge tag 'i3c/for-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni:
"The silvaco driver gets support for the integration of the IP in the
Nuvoton npcm845 SoC. There is also a fix for a possible NULL pointer
dereference that can happen with early IBIs. Summary:
Core:
- Fix a possible NULL pointer dereference due to IBI coming when the
target driver is not yet probed.
Drivers:
- mipi-i3c-hci: Use I2C DMA-safe api
- svc: add Nuvoton npcm845 support"
* tag 'i3c/for-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux:
i3c: Add NULL pointer check in i3c_master_queue_ibi()
i3c: master: Drop duplicate check before calling OF APIs
i3c: master: svc: Fix implicit fallthrough in svc_i3c_master_ibi_work()
i3c: master: svc: Fix missing STOP for master request
i3c: master: svc: Use readsb helper for reading MDB
i3c: master: svc: Fix missing the IBI rules
i3c: master: svc: Fix i3c_master_get_free_addr return check
i3c: master: svc: Fix npcm845 DAA process corruption
i3c: master: svc: Fix npcm845 invalid slvstart event
i3c: master: svc: Fix npcm845 FIFO empty issue
i3c: master: svc: Add support for Nuvoton npcm845 i3c
dt-bindings: i3c: silvaco: Add npcm845 compatible string
dt-bindings: i3c: dw: Add power-domains
i3c: master: svc: Flush FIFO before sending Dynamic Address Assignment(DAA)
i3c: mipi-i3c-hci: Use I2C DMA-safe api
i3c: Remove the const qualifier from i2c_msg pointer in i2c_xfers API
MAINTAINERS: Add Frank Li to Silvaco I3C
MAINTAINERS: Remove Conor Culhane from Silvaco I3C
-rw-r--r-- | CREDITS | 4 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml | 4 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml | 3 | ||||
-rw-r--r-- | MAINTAINERS | 4 | ||||
-rw-r--r-- | drivers/i3c/master.c | 21 | ||||
-rw-r--r-- | drivers/i3c/master/dw-i3c-master.c | 2 | ||||
-rw-r--r-- | drivers/i3c/master/i3c-master-cdns.c | 2 | ||||
-rw-r--r-- | drivers/i3c/master/mipi-i3c-hci/core.c | 10 | ||||
-rw-r--r-- | drivers/i3c/master/svc-i3c-master.c | 138 | ||||
-rw-r--r-- | include/linux/i3c/master.h | 2 |
10 files changed, 154 insertions, 36 deletions
@@ -855,6 +855,10 @@ N: John Crispin E: john@phrozen.org D: MediaTek MT7623 Gigabit ethernet support +N: Conor Culhane +E: conor.culhane@silvaco.com +D: Silvaco I3C master driver + N: Laurence Culhane E: loz@holmes.demon.co.uk D: Wrote the initial alpha SLIP code diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml index c56ff77677f1..4fbdcdac0aee 100644 --- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml @@ -14,7 +14,9 @@ allOf: properties: compatible: - const: silvaco,i3c-master-v1 + enum: + - nuvoton,npcm845-i3c + - silvaco,i3c-master-v1 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml b/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml index 4fc13e3c0f75..5f6467375811 100644 --- a/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml @@ -34,6 +34,9 @@ properties: interrupts: maxItems: 1 + power-domains: + maxItems: 1 + required: - compatible - reg diff --git a/MAINTAINERS b/MAINTAINERS index a99738323f71..db55bd41f0ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11265,6 +11265,7 @@ F: drivers/i3c/master/dw* I3C SUBSYSTEM M: Alexandre Belloni <alexandre.belloni@bootlin.com> +R: Frank Li <Frank.Li@nxp.com> L: linux-i3c@lists.infradead.org (moderated for non-subscribers) S: Maintained C: irc://chat.freenode.net/linux-i3c @@ -22106,8 +22107,9 @@ F: drivers/video/fbdev/sm712* SILVACO I3C DUAL-ROLE MASTER M: Miquel Raynal <miquel.raynal@bootlin.com> -M: Conor Culhane <conor.culhane@silvaco.com> +M: Frank Li <Frank.Li@nxp.com> L: linux-i3c@lists.infradead.org (moderated for non-subscribers) +L: imx@lists.linux.dev S: Maintained F: Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml F: drivers/i3c/master/svc-i3c-master.c diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index d5dc4180afbc..fd81871609d9 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -2276,7 +2276,7 @@ static int of_i3c_master_add_dev(struct i3c_master_controller *master, u32 reg[3]; int ret; - if (!master || !node) + if (!master) return -EINVAL; ret = of_property_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg)); @@ -2369,14 +2369,10 @@ static u8 i3c_master_i2c_get_lvr(struct i2c_client *client) { /* Fall back to no spike filters and FM bus mode. */ u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE; + u32 reg[3]; - if (client->dev.of_node) { - u32 reg[3]; - - if (!of_property_read_u32_array(client->dev.of_node, "reg", - reg, ARRAY_SIZE(reg))) - lvr = reg[2]; - } + if (!of_property_read_u32_array(client->dev.of_node, "reg", reg, ARRAY_SIZE(reg))) + lvr = reg[2]; return lvr; } @@ -2486,7 +2482,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master); struct i2c_dev_desc *i2cdev; struct i2c_dev_boardinfo *i2cboardinfo; - int ret, id = -ENODEV; + int ret, id; adap->dev.parent = master->dev.parent; adap->owner = master->dev.parent->driver->owner; @@ -2497,9 +2493,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) adap->timeout = 1000; adap->retries = 3; - if (master->dev.of_node) - id = of_alias_get_id(master->dev.of_node, "i2c"); - + id = of_alias_get_id(master->dev.of_node, "i2c"); if (id >= 0) { adap->nr = id; ret = i2c_add_numbered_adapter(adap); @@ -2561,6 +2555,9 @@ static void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) */ void i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) { + if (!dev->ibi || !slot) + return; + atomic_inc(&dev->ibi->pending_ibis); queue_work(dev->ibi->wq, &slot->work); } diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 2fbf8b2addd0..611c22b72c15 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -1079,7 +1079,7 @@ static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) } static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, - const struct i2c_msg *i2c_xfers, + struct i2c_msg *i2c_xfers, int i2c_nxfers) { struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index fedbe6624a1c..fd3752cea654 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -813,7 +813,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev, } static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, - const struct i2c_msg *xfers, int nxfers) + struct i2c_msg *xfers, int nxfers) { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct cdns_i3c_master *master = to_cdns_i3c_master(m); diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 648c501407ce..a71226d7ca59 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -367,7 +367,7 @@ out: } static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev, - const struct i2c_msg *i2c_xfers, int nxfers) + struct i2c_msg *i2c_xfers, int nxfers) { struct i3c_master_controller *m = i2c_dev_get_master(dev); struct i3c_hci *hci = to_i3c_hci(m); @@ -382,14 +382,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev, return -ENOMEM; for (i = 0; i < nxfers; i++) { - xfer[i].data = i2c_xfers[i].buf; + xfer[i].data = i2c_get_dma_safe_msg_buf(&i2c_xfers[i], 1); xfer[i].data_len = i2c_xfers[i].len; xfer[i].rnw = i2c_xfers[i].flags & I2C_M_RD; hci->cmd->prep_i2c_xfer(hci, dev, &xfer[i]); xfer[i].cmd_desc[0] |= CMD_0_ROC; - ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]); - if (ret) - goto out; } last = i - 1; xfer[last].cmd_desc[0] |= CMD_0_TOC; @@ -412,7 +409,8 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev, out: for (i = 0; i < nxfers; i++) - i3c_hci_free_safe_xfer_buf(hci, &xfer[i]); + i2c_put_dma_safe_msg_buf(xfer[i].data, &i2c_xfers[i], + ret ? false : true); hci_free_xfer(xfer, nxfers); return ret; diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index d6057d8c7dec..85e16de208d3 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -32,6 +32,7 @@ #define SVC_I3C_MCONFIG_ODBAUD(x) FIELD_PREP(GENMASK(23, 16), (x)) #define SVC_I3C_MCONFIG_ODHPP(x) FIELD_PREP(BIT(24), (x)) #define SVC_I3C_MCONFIG_SKEW(x) FIELD_PREP(GENMASK(27, 25), (x)) +#define SVC_I3C_MCONFIG_SKEW_MASK GENMASK(27, 25) #define SVC_I3C_MCONFIG_I2CBAUD(x) FIELD_PREP(GENMASK(31, 28), (x)) #define SVC_I3C_MCTRL 0x084 @@ -58,6 +59,7 @@ #define SVC_I3C_MSTATUS 0x088 #define SVC_I3C_MSTATUS_STATE(x) FIELD_GET(GENMASK(2, 0), (x)) #define SVC_I3C_MSTATUS_STATE_DAA(x) (SVC_I3C_MSTATUS_STATE(x) == 5) +#define SVC_I3C_MSTATUS_STATE_SLVREQ(x) (SVC_I3C_MSTATUS_STATE(x) == 1) #define SVC_I3C_MSTATUS_STATE_IDLE(x) (SVC_I3C_MSTATUS_STATE(x) == 0) #define SVC_I3C_MSTATUS_BETWEEN(x) FIELD_GET(BIT(4), (x)) #define SVC_I3C_MSTATUS_NACKED(x) FIELD_GET(BIT(5), (x)) @@ -113,6 +115,7 @@ #define SVC_I3C_MWDATAHE 0x0BC #define SVC_I3C_MRDATAB 0x0C0 #define SVC_I3C_MRDATAH 0x0C8 +#define SVC_I3C_MWDATAB1 0x0CC #define SVC_I3C_MWMSG_SDR 0x0D0 #define SVC_I3C_MRMSG_SDR 0x0D4 #define SVC_I3C_MWMSG_DDR 0x0D8 @@ -133,6 +136,32 @@ #define SVC_I3C_EVENT_IBI GENMASK(7, 0) #define SVC_I3C_EVENT_HOTJOIN BIT(31) +/* + * SVC_I3C_QUIRK_FIFO_EMPTY: + * I3C HW stalls the write transfer if the transmit FIFO becomes empty, + * when new data is written to FIFO, I3C HW resumes the transfer but + * the first transmitted data bit may have the wrong value. + * Workaround: + * Fill the FIFO in advance to prevent FIFO from becoming empty. + */ +#define SVC_I3C_QUIRK_FIFO_EMPTY BIT(0) +/* + * SVC_I3C_QUIRK_FLASE_SLVSTART: + * I3C HW may generate an invalid SlvStart event when emitting a STOP. + * If it is a true SlvStart, the MSTATUS state is SLVREQ. + */ +#define SVC_I3C_QUIRK_FALSE_SLVSTART BIT(1) +/* + * SVC_I3C_QUIRK_DAA_CORRUPT: + * When MCONFIG.SKEW=0 and MCONFIG.ODHPP=0, the ENTDAA transaction gets + * corrupted and results in a no repeated-start condition at the end of + * address assignment. + * Workaround: + * Set MCONFIG.SKEW to 1 before initiating the DAA process. After the DAA + * process is completed, return MCONFIG.SKEW to its previous value. + */ +#define SVC_I3C_QUIRK_DAA_CORRUPT BIT(2) + struct svc_i3c_cmd { u8 addr; bool rnw; @@ -158,6 +187,10 @@ struct svc_i3c_regs_save { u32 mdynaddr; }; +struct svc_i3c_drvdata { + u32 quirks; +}; + /** * struct svc_i3c_master - Silvaco I3C Master structure * @base: I3C master controller @@ -183,6 +216,7 @@ struct svc_i3c_regs_save { * @ibi.tbq_slot: To be queued IBI slot * @ibi.lock: IBI lock * @lock: Transfer lock, protect between IBI work thread and callbacks from master + * @drvdata: Driver data * @enabled_events: Bit masks for enable events (IBI, HotJoin). * @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back. */ @@ -214,6 +248,7 @@ struct svc_i3c_master { spinlock_t lock; } ibi; struct mutex lock; + const struct svc_i3c_drvdata *drvdata; u32 enabled_events; u32 mctrl_config; }; @@ -230,6 +265,18 @@ struct svc_i3c_i2c_dev_data { struct i3c_generic_ibi_pool *ibi_pool; }; +static inline bool svc_has_quirk(struct svc_i3c_master *master, u32 quirk) +{ + return (master->drvdata->quirks & quirk); +} + +static inline bool svc_has_daa_corrupt(struct svc_i3c_master *master) +{ + return ((master->drvdata->quirks & SVC_I3C_QUIRK_DAA_CORRUPT) && + !(master->mctrl_config & + (SVC_I3C_MCONFIG_SKEW_MASK | SVC_I3C_MCONFIG_ODHPP(1)))); +} + static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask) { return !!(master->enabled_events & mask); @@ -378,7 +425,7 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master, slot->len < SVC_I3C_FIFO_SIZE) { mdatactrl = readl(master->regs + SVC_I3C_MDATACTRL); count = SVC_I3C_MDATACTRL_RXCOUNT(mdatactrl); - readsl(master->regs + SVC_I3C_MRDATAB, buf, count); + readsb(master->regs + SVC_I3C_MRDATAB, buf, count); slot->len += count; buf += count; } @@ -545,6 +592,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) queue_work(master->base.wq, &master->hj_work); break; case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: + svc_i3c_master_emit_stop(master); + break; default: break; } @@ -564,6 +613,11 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) /* Clear the interrupt status */ writel(SVC_I3C_MINT_SLVSTART, master->regs + SVC_I3C_MSTATUS); + /* Ignore the false event */ + if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART) && + !SVC_I3C_MSTATUS_STATE_SLVREQ(active)) + return IRQ_HANDLED; + svc_i3c_master_disable_interrupts(master); /* Handle the interrupt in a non atomic context */ @@ -888,10 +942,12 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, u8 *addrs, unsigned int *count) { u64 prov_id[SVC_I3C_MAX_DEVS] = {}, nacking_prov_id = 0; - unsigned int dev_nb = 0, last_addr = 0; + unsigned int dev_nb = 0, last_addr = 0, dyn_addr = 0; u32 reg; int ret, i; + svc_i3c_master_flush_fifo(master); + while (true) { /* clean SVC_I3C_MINT_IBIWON w1c bits */ writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); @@ -932,6 +988,26 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, u8 data[6]; /* + * One slave sends its ID to request for address assignment, + * prefilling the dynamic address can reduce SCL clock stalls + * and also fix the SVC_I3C_QUIRK_FIFO_EMPTY quirk. + * + * Ideally, prefilling before the processDAA command is better. + * However, it requires an additional check to write the dyn_addr + * at the right time because the driver needs to write the processDAA + * command twice for one assignment. + * Prefilling here is safe and efficient because the FIFO starts + * filling within a few hundred nanoseconds, which is significantly + * faster compared to the 64 SCL clock cycles. + */ + ret = i3c_master_get_free_addr(&master->base, last_addr + 1); + if (ret < 0) + break; + + dyn_addr = ret; + writel(dyn_addr, master->regs + SVC_I3C_MWDATAB); + + /* * We only care about the 48-bit provisioned ID yet to * be sure a device does not nack an address twice. * Otherwise, we would just need to flush the RX FIFO. @@ -1009,21 +1085,16 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, if (ret) break; - /* Give the slave device a suitable dynamic address */ - ret = i3c_master_get_free_addr(&master->base, last_addr + 1); - if (ret < 0) - break; - - addrs[dev_nb] = ret; + addrs[dev_nb] = dyn_addr; dev_dbg(master->dev, "DAA: device %d assigned to 0x%02x\n", dev_nb, addrs[dev_nb]); - - writel(addrs[dev_nb], master->regs + SVC_I3C_MWDATAB); last_addr = addrs[dev_nb++]; } /* Need manual issue STOP except for Complete condition */ svc_i3c_master_emit_stop(master); + svc_i3c_master_flush_fifo(master); + return ret; } @@ -1037,7 +1108,7 @@ static int svc_i3c_update_ibirules(struct svc_i3c_master *master) /* Create the IBIRULES register for both cases */ i3c_bus_for_each_i3cdev(&master->base.bus, dev) { - if (I3C_BCR_DEVICE_ROLE(dev->info.bcr) == I3C_BCR_I3C_MASTER) + if (!(dev->info.bcr & I3C_BCR_IBI_REQ_CAP)) continue; if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) { @@ -1096,7 +1167,16 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m) } spin_lock_irqsave(&master->xferqueue.lock, flags); + + if (svc_has_daa_corrupt(master)) + writel(master->mctrl_config | SVC_I3C_MCONFIG_SKEW(1), + master->regs + SVC_I3C_MCONFIG); + ret = svc_i3c_master_do_daa_locked(master, addrs, &dev_nb); + + if (svc_has_daa_corrupt(master)) + writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG); + spin_unlock_irqrestore(&master->xferqueue.lock, flags); svc_i3c_master_clear_merrwarn(master); @@ -1220,6 +1300,24 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, SVC_I3C_MCTRL_RDTERM(*actual_len), master->regs + SVC_I3C_MCTRL); + /* + * The entire transaction can consist of multiple write transfers. + * Prefilling before EmitStartAddr causes the data to be emitted + * immediately, becoming part of the previous transfer. + * The only way to work around this hardware issue is to let the + * FIFO start filling as soon as possible after EmitStartAddr. + */ + if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) { + u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END; + u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE); + + writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1); + /* Mark END bit if this is the last byte */ + writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB); + xfer_len -= len; + out += len; + } + ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg, SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); if (ret) @@ -1308,6 +1406,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, emit_stop: svc_i3c_master_emit_stop(master); svc_i3c_master_clear_merrwarn(master); + svc_i3c_master_flush_fifo(master); return ret; } @@ -1584,7 +1683,7 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev, } static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, - const struct i2c_msg *xfers, + struct i2c_msg *xfers, int nxfers) { struct i3c_master_controller *m = i2c_dev_get_master(dev); @@ -1817,6 +1916,10 @@ static int svc_i3c_master_probe(struct platform_device *pdev) if (!master) return -ENOMEM; + master->drvdata = of_device_get_match_data(dev); + if (!master->drvdata) + return -EINVAL; + master->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(master->regs)) return PTR_ERR(master->regs); @@ -1958,8 +2061,17 @@ static const struct dev_pm_ops svc_i3c_pm_ops = { svc_i3c_runtime_resume, NULL) }; +static const struct svc_i3c_drvdata npcm845_drvdata = { + .quirks = SVC_I3C_QUIRK_FIFO_EMPTY | + SVC_I3C_QUIRK_FALSE_SLVSTART | + SVC_I3C_QUIRK_DAA_CORRUPT, +}; + +static const struct svc_i3c_drvdata svc_default_drvdata = {}; + static const struct of_device_id svc_i3c_master_of_match_tbl[] = { - { .compatible = "silvaco,i3c-master-v1"}, + { .compatible = "nuvoton,npcm845-i3c", .data = &npcm845_drvdata }, + { .compatible = "silvaco,i3c-master-v1", .data = &svc_default_drvdata }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 12d532b012c5..c67922ece617 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -475,7 +475,7 @@ struct i3c_master_controller_ops { int (*attach_i2c_dev)(struct i2c_dev_desc *dev); void (*detach_i2c_dev)(struct i2c_dev_desc *dev); int (*i2c_xfers)(struct i2c_dev_desc *dev, - const struct i2c_msg *xfers, int nxfers); + struct i2c_msg *xfers, int nxfers); int (*request_ibi)(struct i3c_dev_desc *dev, const struct i3c_ibi_setup *req); void (*free_ibi)(struct i3c_dev_desc *dev); |