summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Lukwinski <zbigniew.lukwinski@linux.intel.com>2022-05-10 18:37:55 +0300
committerZbigniew Lukwinski <zbigniew.lukwinski@linux.intel.com>2022-05-20 14:49:59 +0300
commit8dcd772516812e8dd37fdf748b1724726b9fd31d (patch)
treeb2d89068298cf5f5095b3b6b6eaff716e4f80f55
parentefe6d9649b1d6b85b50cef64745df2e6749a8a45 (diff)
downloadlinux-8dcd772516812e8dd37fdf748b1724726b9fd31d.tar.xz
i3c: master: Enable support for PEC
PEC (Packet Error Check) support enabled in I3C controller driver. API for I3C device driver to control (enable or disable) PEC support in lower layer driver added. Signed-off-by: Zbigniew Lukwinski <zbigniew.lukwinski@linux.intel.com>
-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;