mirror of
https://github.com/torvalds/linux.git
synced 2026-01-12 00:42:35 +08:00
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>
This commit is contained in:
committed by
Alexandre Belloni
parent
de53ad6ca4
commit
256a21743d
@@ -15,12 +15,12 @@
|
||||
#include "internals.h"
|
||||
|
||||
/**
|
||||
* i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a
|
||||
* specific device
|
||||
* i3c_device_do_xfers() - do I3C transfers directed to a specific device
|
||||
*
|
||||
* @dev: device with which the transfers should be done
|
||||
* @xfers: array of transfers
|
||||
* @nxfers: number of transfers
|
||||
* @mode: transfer mode
|
||||
*
|
||||
* Initiate one or several private SDR transfers with @dev.
|
||||
*
|
||||
@@ -33,9 +33,8 @@
|
||||
* 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
|
||||
* 5.1.2.2.3.
|
||||
*/
|
||||
int i3c_device_do_priv_xfers(struct i3c_device *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers)
|
||||
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
|
||||
int nxfers, enum i3c_xfer_mode mode)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
@@ -48,12 +47,12 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
|
||||
}
|
||||
|
||||
i3c_bus_normaluse_lock(dev->bus);
|
||||
ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
|
||||
ret = i3c_dev_do_xfers_locked(dev->desc, xfers, nxfers, mode);
|
||||
i3c_bus_normaluse_unlock(dev->bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
|
||||
EXPORT_SYMBOL_GPL(i3c_device_do_xfers);
|
||||
|
||||
/**
|
||||
* i3c_device_do_setdasa() - do I3C dynamic address assignement with
|
||||
@@ -260,6 +259,20 @@ i3c_device_match_id(struct i3c_device *i3cdev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_device_match_id);
|
||||
|
||||
/**
|
||||
* i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
|
||||
* connected master controller.
|
||||
* @dev: I3C device
|
||||
*
|
||||
* Return: a bit mask, which supported transfer mode, bit position is defined at
|
||||
* enum i3c_hdr_mode
|
||||
*/
|
||||
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
|
||||
{
|
||||
return i3c_dev_get_master(dev->desc)->this->info.hdr_cap | BIT(I3C_SDR);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
|
||||
|
||||
/**
|
||||
* i3c_driver_register_with_owner() - register an I3C device driver
|
||||
*
|
||||
|
||||
@@ -15,9 +15,9 @@ void i3c_bus_normaluse_lock(struct i3c_bus *bus);
|
||||
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
|
||||
|
||||
int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev);
|
||||
int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers);
|
||||
int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev,
|
||||
struct i3c_xfer *xfers,
|
||||
int nxfers, enum i3c_xfer_mode mode);
|
||||
int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev);
|
||||
int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
|
||||
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
|
||||
|
||||
@@ -2819,10 +2819,14 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
|
||||
|
||||
static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
|
||||
{
|
||||
if (!ops || !ops->bus_init || !ops->priv_xfers ||
|
||||
if (!ops || !ops->bus_init ||
|
||||
!ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers)
|
||||
return -EINVAL;
|
||||
|
||||
/* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */
|
||||
if (!ops->priv_xfers && !ops->i3c_xfers)
|
||||
return -EINVAL;
|
||||
|
||||
if (ops->request_ibi &&
|
||||
(!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi ||
|
||||
!ops->recycle_ibi_slot))
|
||||
@@ -3012,9 +3016,8 @@ int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev)
|
||||
dev->boardinfo->init_dyn_addr);
|
||||
}
|
||||
|
||||
int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers)
|
||||
int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
|
||||
int nxfers, enum i3c_xfer_mode mode)
|
||||
{
|
||||
struct i3c_master_controller *master;
|
||||
|
||||
@@ -3025,9 +3028,15 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
|
||||
if (!master || !xfers)
|
||||
return -EINVAL;
|
||||
|
||||
if (!master->ops->priv_xfers)
|
||||
if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (master->ops->i3c_xfers)
|
||||
return master->ops->i3c_xfers(dev, xfers, nxfers, mode);
|
||||
|
||||
if (mode != I3C_SDR)
|
||||
return -EINVAL;
|
||||
|
||||
return master->ops->priv_xfers(dev, xfers, nxfers);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,20 +39,25 @@ enum i3c_error_code {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum i3c_hdr_mode - HDR mode ids
|
||||
* enum i3c_xfer_mode - I3C xfer mode ids
|
||||
* @I3C_HDR_DDR: DDR mode
|
||||
* @I3C_HDR_TSP: TSP mode
|
||||
* @I3C_HDR_TSL: TSL mode
|
||||
* @I3C_SDR: SDR mode (NOT HDR mode)
|
||||
*/
|
||||
enum i3c_hdr_mode {
|
||||
I3C_HDR_DDR,
|
||||
I3C_HDR_TSP,
|
||||
I3C_HDR_TSL,
|
||||
enum i3c_xfer_mode {
|
||||
/* The below 3 value (I3C_HDR*) must match GETCAP1 Byte bit position */
|
||||
I3C_HDR_DDR = 0,
|
||||
I3C_HDR_TSP = 1,
|
||||
I3C_HDR_TSL = 2,
|
||||
/* Use for default SDR transfer mode */
|
||||
I3C_SDR = 0x31,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct i3c_priv_xfer - I3C SDR private transfer
|
||||
* struct i3c_xfer - I3C data transfer
|
||||
* @rnw: encodes the transfer direction. true for a read, false for a write
|
||||
* @cmd: Read/Write command in HDR mode, read: 0x80 - 0xff, write: 0x00 - 0x7f
|
||||
* @len: transfer length in bytes of the transfer
|
||||
* @actual_len: actual length in bytes are transferred by the controller
|
||||
* @data: input/output buffer
|
||||
@@ -60,8 +65,11 @@ enum i3c_hdr_mode {
|
||||
* @data.out: output buffer. Must point to a DMA-able buffer
|
||||
* @err: I3C error code
|
||||
*/
|
||||
struct i3c_priv_xfer {
|
||||
u8 rnw;
|
||||
struct i3c_xfer {
|
||||
union {
|
||||
u8 rnw;
|
||||
u8 cmd;
|
||||
};
|
||||
u16 len;
|
||||
u16 actual_len;
|
||||
union {
|
||||
@@ -71,6 +79,9 @@ struct i3c_priv_xfer {
|
||||
enum i3c_error_code err;
|
||||
};
|
||||
|
||||
/* keep back compatible */
|
||||
#define i3c_priv_xfer i3c_xfer
|
||||
|
||||
/**
|
||||
* enum i3c_dcr - I3C DCR values
|
||||
* @I3C_DCR_GENERIC_DEVICE: generic I3C device
|
||||
@@ -297,9 +308,15 @@ static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
|
||||
i3c_i2c_driver_unregister, \
|
||||
__i2cdrv)
|
||||
|
||||
int i3c_device_do_priv_xfers(struct i3c_device *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers);
|
||||
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
|
||||
int nxfers, enum i3c_xfer_mode mode);
|
||||
|
||||
static inline int i3c_device_do_priv_xfers(struct i3c_device *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers)
|
||||
{
|
||||
return i3c_device_do_xfers(dev, xfers, nxfers, I3C_SDR);
|
||||
}
|
||||
|
||||
int i3c_device_do_setdasa(struct i3c_device *dev);
|
||||
|
||||
@@ -341,5 +358,6 @@ int i3c_device_request_ibi(struct i3c_device *dev,
|
||||
void i3c_device_free_ibi(struct i3c_device *dev);
|
||||
int i3c_device_enable_ibi(struct i3c_device *dev);
|
||||
int i3c_device_disable_ibi(struct i3c_device *dev);
|
||||
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev);
|
||||
|
||||
#endif /* I3C_DEV_H */
|
||||
|
||||
@@ -474,9 +474,13 @@ struct i3c_master_controller_ops {
|
||||
const struct i3c_ccc_cmd *cmd);
|
||||
int (*send_ccc_cmd)(struct i3c_master_controller *master,
|
||||
struct i3c_ccc_cmd *cmd);
|
||||
/* Deprecated, please use i3c_xfers() */
|
||||
int (*priv_xfers)(struct i3c_dev_desc *dev,
|
||||
struct i3c_priv_xfer *xfers,
|
||||
int nxfers);
|
||||
int (*i3c_xfers)(struct i3c_dev_desc *dev,
|
||||
struct i3c_xfer *xfers,
|
||||
int nxfers, enum i3c_xfer_mode mode);
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user