diff options
-rw-r--r-- | drivers/i3c/device.c | 18 | ||||
-rw-r--r-- | drivers/i3c/internals.h | 1 | ||||
-rw-r--r-- | drivers/i3c/master.c | 20 | ||||
-rw-r--r-- | include/linux/i3c/device.h | 5 | ||||
-rw-r--r-- | include/linux/i3c/master.h | 1 |
5 files changed, 45 insertions, 0 deletions
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index be6669cf0846..cf2055dc238c 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -330,3 +330,21 @@ int i3c_device_getstatus_ccc(struct i3c_device *dev, struct i3c_device_info *inf return ret; } EXPORT_SYMBOL_GPL(i3c_device_getstatus_ccc); + +/** + * i3c_device_control_pec() - enable or disable PEC support in HW + * + * @dev: I3C device to get the status for + * @pec: flag telling whether PEC support shall be enabled or disabled + * + * Try to enable or disable HW support for PEC (Packet Error Check). + * In case no HW support for PEC, software implementation could be used. + * + * Return: 0 in case of success, -EOPNOTSUPP in case PEC is not supported by HW, + * other negative error codes when PEC enabling failed. + */ +int i3c_device_control_pec(struct i3c_device *dev, bool pec) +{ + return i3c_dev_control_pec(dev->desc, pec); +} +EXPORT_SYMBOL_GPL(i3c_device_control_pec); diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h index 524ad47fd916..5e6bd53637e4 100644 --- a/drivers/i3c/internals.h +++ b/drivers/i3c/internals.h @@ -28,4 +28,5 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev); int i3c_dev_getstatus_locked(struct i3c_dev_desc *dev, struct i3c_device_info *info); int i3c_for_each_dev(void *data, int (*fn)(struct device *, void *)); int i3c_dev_generate_ibi_locked(struct i3c_dev_desc *dev, const u8 *data, int len); +int i3c_dev_control_pec(struct i3c_dev_desc *dev, bool pec); #endif /* I3C_INTERNAL_H */ diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 656f0398d3e5..8ad15e2dcc62 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -3048,6 +3048,26 @@ int i3c_for_each_dev(void *data, int (*fn)(struct device *, void *)) } EXPORT_SYMBOL_GPL(i3c_for_each_dev); +int i3c_dev_control_pec(struct i3c_dev_desc *dev, bool pec) +{ + struct i3c_master_controller *master = i3c_dev_get_master(dev); + + if (!master->pec_supported) + return -EOPNOTSUPP; + + dev->info.pec = pec; + + /* + * TODO: There are two cases which shall be covered + * 1. Controller doesn't support PEC. + * In this case we could just fallback to SW implementation. + * 2. Device doesn't support PEC. + * Then we really can't use PEC - and should error-out. + */ + + return 0; +} + static int __init i3c_init(void) { return bus_register(&i3c_bus_type); diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index e036a30f8c7e..1bc9f65dbb6a 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -109,6 +109,8 @@ enum i3c_dcr { * @max_read_turnaround: max read turn-around time in micro-seconds * @max_read_len: max private SDR read length in bytes * @max_write_len: max private SDR write length in bytes + * @pec: flag telling whether PEC (Packet Error Check) generation and verification for read + * and write transaction is enabled * * These are all basic information that should be advertised by an I3C device. * Some of them are optional depending on the device type and device @@ -130,6 +132,7 @@ struct i3c_device_info { u32 max_read_turnaround; u16 max_read_len; u16 max_write_len; + u8 pec; __be16 status; }; @@ -346,4 +349,6 @@ struct i3c_target_read_setup { int i3c_target_read_register(struct i3c_device *dev, const struct i3c_target_read_setup *setup); +int i3c_device_control_pec(struct i3c_device *dev, bool pec); + #endif /* I3C_DEV_H */ diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 5d35a6d1c992..c9e7a2084f1e 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -500,6 +500,7 @@ struct i3c_master_controller { struct i2c_adapter i2c; const struct i3c_master_controller_ops *ops; const struct i3c_target_ops *target_ops; + unsigned int pec_supported : 1; unsigned int target : 1; unsigned int secondary : 1; unsigned int init_done : 1; |