summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/i3c/device.c18
-rw-r--r--drivers/i3c/internals.h1
-rw-r--r--drivers/i3c/master.c20
-rw-r--r--include/linux/i3c/device.h5
-rw-r--r--include/linux/i3c/master.h1
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;