diff options
| -rw-r--r-- | drivers/i3c/device.c | 27 | ||||
| -rw-r--r-- | drivers/i3c/internals.h | 6 | ||||
| -rw-r--r-- | drivers/i3c/master.c | 19 | ||||
| -rw-r--r-- | include/linux/i3c/device.h | 40 | ||||
| -rw-r--r-- | include/linux/i3c/master.h | 4 |
5 files changed, 70 insertions, 26 deletions
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 2396545763ff..8a156f5ad692 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -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 @@ -261,6 +260,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 * * @drv: driver to register diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h index 79ceaa5f5afd..f609e5098137 100644 --- a/drivers/i3c/internals.h +++ b/drivers/i3c/internals.h @@ -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, diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 823661a81f5e..f88f7e19203a 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -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); } diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 7f136de4b73e..7f7738041f38 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -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 */ diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index c52a82dd79a6..d0d5b3a9049f 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.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, |
