summaryrefslogtreecommitdiff
path: root/drivers/i3c/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i3c/device.c')
-rw-r--r--drivers/i3c/device.c108
1 files changed, 93 insertions, 15 deletions
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index 69cc040c3a1c..8a156f5ad692 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -15,22 +15,26 @@
#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.
*
* This function can sleep and thus cannot be called in atomic context.
*
- * Return: 0 in case of success, a negative error core otherwise.
+ * Return:
+ * * 0 in case of success, a negative error core otherwise.
+ * * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or
+ * controller role request) win the bus. Client driver needs to resend the
+ * '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;
@@ -43,12 +47,32 @@ 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
+ * static address
+ *
+ * @dev: device with which the DAA should be done
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_do_setdasa(struct i3c_device *dev)
+{
+ int ret;
+
+ i3c_bus_normaluse_lock(dev->bus);
+ ret = i3c_dev_setdasa_locked(dev->desc);
+ i3c_bus_normaluse_unlock(dev->bus);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_do_setdasa);
/**
* i3c_device_get_info() - get I3C device information
@@ -58,7 +82,7 @@ EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
*
* Retrieve I3C dev info.
*/
-void i3c_device_get_info(struct i3c_device *dev,
+void i3c_device_get_info(const struct i3c_device *dev,
struct i3c_device_info *info)
{
if (!info)
@@ -189,16 +213,65 @@ struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
EXPORT_SYMBOL_GPL(i3cdev_to_dev);
/**
- * dev_to_i3cdev() - Returns the I3C device containing @dev
- * @dev: device object
+ * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
+ * @i3cdev: I3C device
+ * @id_table: I3C device match table
*
- * Return: a pointer to an I3C device object.
+ * Return: a pointer to an i3c_device_id object or NULL if there's no match.
*/
-struct i3c_device *dev_to_i3cdev(struct device *dev)
+const struct i3c_device_id *
+i3c_device_match_id(struct i3c_device *i3cdev,
+ const struct i3c_device_id *id_table)
{
- return container_of(dev, struct i3c_device, dev);
+ struct i3c_device_info devinfo;
+ const struct i3c_device_id *id;
+ u16 manuf, part, ext_info;
+ bool rndpid;
+
+ i3c_device_get_info(i3cdev, &devinfo);
+
+ manuf = I3C_PID_MANUF_ID(devinfo.pid);
+ part = I3C_PID_PART_ID(devinfo.pid);
+ ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
+ rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
+
+ for (id = id_table; id->match_flags != 0; id++) {
+ if ((id->match_flags & I3C_MATCH_DCR) &&
+ id->dcr != devinfo.dcr)
+ continue;
+
+ if ((id->match_flags & I3C_MATCH_MANUF) &&
+ id->manuf_id != manuf)
+ continue;
+
+ if ((id->match_flags & I3C_MATCH_PART) &&
+ (rndpid || id->part_id != part))
+ continue;
+
+ if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
+ (rndpid || id->extra_info != ext_info))
+ continue;
+
+ return id;
+ }
+
+ return NULL;
+}
+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(dev_to_i3cdev);
+EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
/**
* i3c_driver_register_with_owner() - register an I3C device driver
@@ -215,6 +288,11 @@ int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
drv->driver.owner = owner;
drv->driver.bus = &i3c_bus_type;
+ if (!drv->probe) {
+ pr_err("Trying to register an i3c driver without probe callback\n");
+ return -EINVAL;
+ }
+
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);