diff options
Diffstat (limited to 'drivers/i3c/device.c')
| -rw-r--r-- | drivers/i3c/device.c | 108 |
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); |
