Skip to content

Commit 256a217

Browse files
nxpfranklialexandrebelloni
authored andcommitted
i3c: Add HDR API support
Rename struct i3c_priv_xfer to struct i3c_xfer, since private xfer in the I3C spec refers only to SDR transfers. Ref: i3c spec ver1.2, section 3, Technical Overview. i3c_xfer will be used for both SDR and HDR. Rename enum i3c_hdr_mode to i3c_xfer_mode. Previous definition need match CCC GET_CAP1 bit position. Use 31 as SDR transfer mode. Add i3c_device_do_xfers() with an xfer mode argument, while keeping i3c_device_do_priv_xfers() as a wrapper that calls i3c_device_do_xfers() with I3C_SDR for backward compatibility. Introduce a 'cmd' field in struct i3c_xfer as an anonymous union with 'rnw', since HDR mode uses read/write commands instead of the SDR address bit. Add .i3c_xfers() callback for master controllers. If not implemented, fall back to SDR with .priv_xfers(). The .priv_xfers() API can be removed once all controllers switch to .i3c_xfers(). Add 'mode_mask' bitmask to advertise controller capability. Signed-off-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20251106-i3c_ddr-v11-1-33a6a66ed095@nxp.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent de53ad6 commit 256a217

5 files changed

Lines changed: 70 additions & 26 deletions

File tree

drivers/i3c/device.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
#include "internals.h"
1616

1717
/**
18-
* i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a
19-
* specific device
18+
* i3c_device_do_xfers() - do I3C transfers directed to a specific device
2019
*
2120
* @dev: device with which the transfers should be done
2221
* @xfers: array of transfers
2322
* @nxfers: number of transfers
23+
* @mode: transfer mode
2424
*
2525
* Initiate one or several private SDR transfers with @dev.
2626
*
@@ -33,9 +33,8 @@
3333
* 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
3434
* 5.1.2.2.3.
3535
*/
36-
int i3c_device_do_priv_xfers(struct i3c_device *dev,
37-
struct i3c_priv_xfer *xfers,
38-
int nxfers)
36+
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
37+
int nxfers, enum i3c_xfer_mode mode)
3938
{
4039
int ret, i;
4140

@@ -48,12 +47,12 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
4847
}
4948

5049
i3c_bus_normaluse_lock(dev->bus);
51-
ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
50+
ret = i3c_dev_do_xfers_locked(dev->desc, xfers, nxfers, mode);
5251
i3c_bus_normaluse_unlock(dev->bus);
5352

5453
return ret;
5554
}
56-
EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
55+
EXPORT_SYMBOL_GPL(i3c_device_do_xfers);
5756

5857
/**
5958
* i3c_device_do_setdasa() - do I3C dynamic address assignement with
@@ -260,6 +259,20 @@ i3c_device_match_id(struct i3c_device *i3cdev,
260259
}
261260
EXPORT_SYMBOL_GPL(i3c_device_match_id);
262261

262+
/**
263+
* i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
264+
* connected master controller.
265+
* @dev: I3C device
266+
*
267+
* Return: a bit mask, which supported transfer mode, bit position is defined at
268+
* enum i3c_hdr_mode
269+
*/
270+
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
271+
{
272+
return i3c_dev_get_master(dev->desc)->this->info.hdr_cap | BIT(I3C_SDR);
273+
}
274+
EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
275+
263276
/**
264277
* i3c_driver_register_with_owner() - register an I3C device driver
265278
*

drivers/i3c/internals.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ void i3c_bus_normaluse_lock(struct i3c_bus *bus);
1515
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
1616

1717
int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev);
18-
int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
19-
struct i3c_priv_xfer *xfers,
20-
int nxfers);
18+
int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev,
19+
struct i3c_xfer *xfers,
20+
int nxfers, enum i3c_xfer_mode mode);
2121
int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev);
2222
int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
2323
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,

drivers/i3c/master.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,10 +2819,14 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
28192819

28202820
static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
28212821
{
2822-
if (!ops || !ops->bus_init || !ops->priv_xfers ||
2822+
if (!ops || !ops->bus_init ||
28232823
!ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers)
28242824
return -EINVAL;
28252825

2826+
/* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */
2827+
if (!ops->priv_xfers && !ops->i3c_xfers)
2828+
return -EINVAL;
2829+
28262830
if (ops->request_ibi &&
28272831
(!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi ||
28282832
!ops->recycle_ibi_slot))
@@ -3012,9 +3016,8 @@ int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev)
30123016
dev->boardinfo->init_dyn_addr);
30133017
}
30143018

3015-
int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
3016-
struct i3c_priv_xfer *xfers,
3017-
int nxfers)
3019+
int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
3020+
int nxfers, enum i3c_xfer_mode mode)
30183021
{
30193022
struct i3c_master_controller *master;
30203023

@@ -3025,9 +3028,15 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
30253028
if (!master || !xfers)
30263029
return -EINVAL;
30273030

3028-
if (!master->ops->priv_xfers)
3031+
if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode)))
30293032
return -EOPNOTSUPP;
30303033

3034+
if (master->ops->i3c_xfers)
3035+
return master->ops->i3c_xfers(dev, xfers, nxfers, mode);
3036+
3037+
if (mode != I3C_SDR)
3038+
return -EINVAL;
3039+
30313040
return master->ops->priv_xfers(dev, xfers, nxfers);
30323041
}
30333042

include/linux/i3c/device.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,37 @@ enum i3c_error_code {
3939
};
4040

4141
/**
42-
* enum i3c_hdr_mode - HDR mode ids
42+
* enum i3c_xfer_mode - I3C xfer mode ids
4343
* @I3C_HDR_DDR: DDR mode
4444
* @I3C_HDR_TSP: TSP mode
4545
* @I3C_HDR_TSL: TSL mode
46+
* @I3C_SDR: SDR mode (NOT HDR mode)
4647
*/
47-
enum i3c_hdr_mode {
48-
I3C_HDR_DDR,
49-
I3C_HDR_TSP,
50-
I3C_HDR_TSL,
48+
enum i3c_xfer_mode {
49+
/* The below 3 value (I3C_HDR*) must match GETCAP1 Byte bit position */
50+
I3C_HDR_DDR = 0,
51+
I3C_HDR_TSP = 1,
52+
I3C_HDR_TSL = 2,
53+
/* Use for default SDR transfer mode */
54+
I3C_SDR = 0x31,
5155
};
5256

5357
/**
54-
* struct i3c_priv_xfer - I3C SDR private transfer
58+
* struct i3c_xfer - I3C data transfer
5559
* @rnw: encodes the transfer direction. true for a read, false for a write
60+
* @cmd: Read/Write command in HDR mode, read: 0x80 - 0xff, write: 0x00 - 0x7f
5661
* @len: transfer length in bytes of the transfer
5762
* @actual_len: actual length in bytes are transferred by the controller
5863
* @data: input/output buffer
5964
* @data.in: input buffer. Must point to a DMA-able buffer
6065
* @data.out: output buffer. Must point to a DMA-able buffer
6166
* @err: I3C error code
6267
*/
63-
struct i3c_priv_xfer {
64-
u8 rnw;
68+
struct i3c_xfer {
69+
union {
70+
u8 rnw;
71+
u8 cmd;
72+
};
6573
u16 len;
6674
u16 actual_len;
6775
union {
@@ -71,6 +79,9 @@ struct i3c_priv_xfer {
7179
enum i3c_error_code err;
7280
};
7381

82+
/* keep back compatible */
83+
#define i3c_priv_xfer i3c_xfer
84+
7485
/**
7586
* enum i3c_dcr - I3C DCR values
7687
* @I3C_DCR_GENERIC_DEVICE: generic I3C device
@@ -297,9 +308,15 @@ static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
297308
i3c_i2c_driver_unregister, \
298309
__i2cdrv)
299310

300-
int i3c_device_do_priv_xfers(struct i3c_device *dev,
301-
struct i3c_priv_xfer *xfers,
302-
int nxfers);
311+
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
312+
int nxfers, enum i3c_xfer_mode mode);
313+
314+
static inline int i3c_device_do_priv_xfers(struct i3c_device *dev,
315+
struct i3c_priv_xfer *xfers,
316+
int nxfers)
317+
{
318+
return i3c_device_do_xfers(dev, xfers, nxfers, I3C_SDR);
319+
}
303320

304321
int i3c_device_do_setdasa(struct i3c_device *dev);
305322

@@ -341,5 +358,6 @@ int i3c_device_request_ibi(struct i3c_device *dev,
341358
void i3c_device_free_ibi(struct i3c_device *dev);
342359
int i3c_device_enable_ibi(struct i3c_device *dev);
343360
int i3c_device_disable_ibi(struct i3c_device *dev);
361+
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev);
344362

345363
#endif /* I3C_DEV_H */

include/linux/i3c/master.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,13 @@ struct i3c_master_controller_ops {
474474
const struct i3c_ccc_cmd *cmd);
475475
int (*send_ccc_cmd)(struct i3c_master_controller *master,
476476
struct i3c_ccc_cmd *cmd);
477+
/* Deprecated, please use i3c_xfers() */
477478
int (*priv_xfers)(struct i3c_dev_desc *dev,
478479
struct i3c_priv_xfer *xfers,
479480
int nxfers);
481+
int (*i3c_xfers)(struct i3c_dev_desc *dev,
482+
struct i3c_xfer *xfers,
483+
int nxfers, enum i3c_xfer_mode mode);
480484
int (*attach_i2c_dev)(struct i2c_dev_desc *dev);
481485
void (*detach_i2c_dev)(struct i2c_dev_desc *dev);
482486
int (*i2c_xfers)(struct i2c_dev_desc *dev,

0 commit comments

Comments
 (0)