13a379bbcSBoris Brezillon // SPDX-License-Identifier: GPL-2.0 23a379bbcSBoris Brezillon /* 33a379bbcSBoris Brezillon * Copyright (C) 2018 Cadence Design Systems Inc. 43a379bbcSBoris Brezillon * 53a379bbcSBoris Brezillon * Author: Boris Brezillon <boris.brezillon@bootlin.com> 63a379bbcSBoris Brezillon */ 73a379bbcSBoris Brezillon 83a379bbcSBoris Brezillon #include <linux/atomic.h> 93a379bbcSBoris Brezillon #include <linux/bug.h> 103a379bbcSBoris Brezillon #include <linux/completion.h> 113a379bbcSBoris Brezillon #include <linux/device.h> 123a379bbcSBoris Brezillon #include <linux/mutex.h> 133a379bbcSBoris Brezillon #include <linux/slab.h> 143a379bbcSBoris Brezillon 153a379bbcSBoris Brezillon #include "internals.h" 163a379bbcSBoris Brezillon 173a379bbcSBoris Brezillon /** 183a379bbcSBoris Brezillon * i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a 193a379bbcSBoris Brezillon * specific device 203a379bbcSBoris Brezillon * 213a379bbcSBoris Brezillon * @dev: device with which the transfers should be done 223a379bbcSBoris Brezillon * @xfers: array of transfers 233a379bbcSBoris Brezillon * @nxfers: number of transfers 243a379bbcSBoris Brezillon * 253a379bbcSBoris Brezillon * Initiate one or several private SDR transfers with @dev. 263a379bbcSBoris Brezillon * 273a379bbcSBoris Brezillon * This function can sleep and thus cannot be called in atomic context. 283a379bbcSBoris Brezillon * 293a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 303a379bbcSBoris Brezillon */ 313a379bbcSBoris Brezillon int i3c_device_do_priv_xfers(struct i3c_device *dev, 323a379bbcSBoris Brezillon struct i3c_priv_xfer *xfers, 333a379bbcSBoris Brezillon int nxfers) 343a379bbcSBoris Brezillon { 353a379bbcSBoris Brezillon int ret, i; 363a379bbcSBoris Brezillon 373a379bbcSBoris Brezillon if (nxfers < 1) 383a379bbcSBoris Brezillon return 0; 393a379bbcSBoris Brezillon 403a379bbcSBoris Brezillon for (i = 0; i < nxfers; i++) { 413a379bbcSBoris Brezillon if (!xfers[i].len || !xfers[i].data.in) 423a379bbcSBoris Brezillon return -EINVAL; 433a379bbcSBoris Brezillon } 443a379bbcSBoris Brezillon 453a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 463a379bbcSBoris Brezillon ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers); 473a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 483a379bbcSBoris Brezillon 493a379bbcSBoris Brezillon return ret; 503a379bbcSBoris Brezillon } 513a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers); 523a379bbcSBoris Brezillon 533a379bbcSBoris Brezillon /** 543a379bbcSBoris Brezillon * i3c_device_get_info() - get I3C device information 553a379bbcSBoris Brezillon * 563a379bbcSBoris Brezillon * @dev: device we want information on 573a379bbcSBoris Brezillon * @info: the information object to fill in 583a379bbcSBoris Brezillon * 593a379bbcSBoris Brezillon * Retrieve I3C dev info. 603a379bbcSBoris Brezillon */ 613a379bbcSBoris Brezillon void i3c_device_get_info(struct i3c_device *dev, 623a379bbcSBoris Brezillon struct i3c_device_info *info) 633a379bbcSBoris Brezillon { 643a379bbcSBoris Brezillon if (!info) 653a379bbcSBoris Brezillon return; 663a379bbcSBoris Brezillon 673a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 683a379bbcSBoris Brezillon if (dev->desc) 693a379bbcSBoris Brezillon *info = dev->desc->info; 703a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 713a379bbcSBoris Brezillon } 723a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_get_info); 733a379bbcSBoris Brezillon 743a379bbcSBoris Brezillon /** 753a379bbcSBoris Brezillon * i3c_device_disable_ibi() - Disable IBIs coming from a specific device 763a379bbcSBoris Brezillon * @dev: device on which IBIs should be disabled 773a379bbcSBoris Brezillon * 783a379bbcSBoris Brezillon * This function disable IBIs coming from a specific device and wait for 793a379bbcSBoris Brezillon * all pending IBIs to be processed. 803a379bbcSBoris Brezillon * 813a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 823a379bbcSBoris Brezillon */ 833a379bbcSBoris Brezillon int i3c_device_disable_ibi(struct i3c_device *dev) 843a379bbcSBoris Brezillon { 853a379bbcSBoris Brezillon int ret = -ENOENT; 863a379bbcSBoris Brezillon 873a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 883a379bbcSBoris Brezillon if (dev->desc) { 893a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 903a379bbcSBoris Brezillon ret = i3c_dev_disable_ibi_locked(dev->desc); 913a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 923a379bbcSBoris Brezillon } 933a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 943a379bbcSBoris Brezillon 953a379bbcSBoris Brezillon return ret; 963a379bbcSBoris Brezillon } 973a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_disable_ibi); 983a379bbcSBoris Brezillon 993a379bbcSBoris Brezillon /** 1003a379bbcSBoris Brezillon * i3c_device_enable_ibi() - Enable IBIs coming from a specific device 1013a379bbcSBoris Brezillon * @dev: device on which IBIs should be enabled 1023a379bbcSBoris Brezillon * 1033a379bbcSBoris Brezillon * This function enable IBIs coming from a specific device and wait for 1043a379bbcSBoris Brezillon * all pending IBIs to be processed. This should be called on a device 1053a379bbcSBoris Brezillon * where i3c_device_request_ibi() has succeeded. 1063a379bbcSBoris Brezillon * 1073a379bbcSBoris Brezillon * Note that IBIs from this device might be received before this function 1083a379bbcSBoris Brezillon * returns to its caller. 1093a379bbcSBoris Brezillon * 1103a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1113a379bbcSBoris Brezillon */ 1123a379bbcSBoris Brezillon int i3c_device_enable_ibi(struct i3c_device *dev) 1133a379bbcSBoris Brezillon { 1143a379bbcSBoris Brezillon int ret = -ENOENT; 1153a379bbcSBoris Brezillon 1163a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1173a379bbcSBoris Brezillon if (dev->desc) { 1183a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1193a379bbcSBoris Brezillon ret = i3c_dev_enable_ibi_locked(dev->desc); 1203a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1213a379bbcSBoris Brezillon } 1223a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1233a379bbcSBoris Brezillon 1243a379bbcSBoris Brezillon return ret; 1253a379bbcSBoris Brezillon } 1263a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_enable_ibi); 1273a379bbcSBoris Brezillon 1283a379bbcSBoris Brezillon /** 1293a379bbcSBoris Brezillon * i3c_device_request_ibi() - Request an IBI 1303a379bbcSBoris Brezillon * @dev: device for which we should enable IBIs 1313a379bbcSBoris Brezillon * @req: setup requested for this IBI 1323a379bbcSBoris Brezillon * 1333a379bbcSBoris Brezillon * This function is responsible for pre-allocating all resources needed to 1343a379bbcSBoris Brezillon * process IBIs coming from @dev. When this function returns, the IBI is not 1353a379bbcSBoris Brezillon * enabled until i3c_device_enable_ibi() is called. 1363a379bbcSBoris Brezillon * 1373a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1383a379bbcSBoris Brezillon */ 1393a379bbcSBoris Brezillon int i3c_device_request_ibi(struct i3c_device *dev, 1403a379bbcSBoris Brezillon const struct i3c_ibi_setup *req) 1413a379bbcSBoris Brezillon { 1423a379bbcSBoris Brezillon int ret = -ENOENT; 1433a379bbcSBoris Brezillon 1443a379bbcSBoris Brezillon if (!req->handler || !req->num_slots) 1453a379bbcSBoris Brezillon return -EINVAL; 1463a379bbcSBoris Brezillon 1473a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1483a379bbcSBoris Brezillon if (dev->desc) { 1493a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1503a379bbcSBoris Brezillon ret = i3c_dev_request_ibi_locked(dev->desc, req); 1513a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1523a379bbcSBoris Brezillon } 1533a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1543a379bbcSBoris Brezillon 1553a379bbcSBoris Brezillon return ret; 1563a379bbcSBoris Brezillon } 1573a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_request_ibi); 1583a379bbcSBoris Brezillon 1593a379bbcSBoris Brezillon /** 1603a379bbcSBoris Brezillon * i3c_device_free_ibi() - Free all resources needed for IBI handling 1613a379bbcSBoris Brezillon * @dev: device on which you want to release IBI resources 1623a379bbcSBoris Brezillon * 1633a379bbcSBoris Brezillon * This function is responsible for de-allocating resources previously 1643a379bbcSBoris Brezillon * allocated by i3c_device_request_ibi(). It should be called after disabling 1653a379bbcSBoris Brezillon * IBIs with i3c_device_disable_ibi(). 1663a379bbcSBoris Brezillon */ 1673a379bbcSBoris Brezillon void i3c_device_free_ibi(struct i3c_device *dev) 1683a379bbcSBoris Brezillon { 1693a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1703a379bbcSBoris Brezillon if (dev->desc) { 1713a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1723a379bbcSBoris Brezillon i3c_dev_free_ibi_locked(dev->desc); 1733a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1743a379bbcSBoris Brezillon } 1753a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1763a379bbcSBoris Brezillon } 1773a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_free_ibi); 1783a379bbcSBoris Brezillon 1793a379bbcSBoris Brezillon /** 1803a379bbcSBoris Brezillon * i3cdev_to_dev() - Returns the device embedded in @i3cdev 1813a379bbcSBoris Brezillon * @i3cdev: I3C device 1823a379bbcSBoris Brezillon * 1833a379bbcSBoris Brezillon * Return: a pointer to a device object. 1843a379bbcSBoris Brezillon */ 1853a379bbcSBoris Brezillon struct device *i3cdev_to_dev(struct i3c_device *i3cdev) 1863a379bbcSBoris Brezillon { 1873a379bbcSBoris Brezillon return &i3cdev->dev; 1883a379bbcSBoris Brezillon } 1893a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3cdev_to_dev); 1903a379bbcSBoris Brezillon 1913a379bbcSBoris Brezillon /** 1923a379bbcSBoris Brezillon * dev_to_i3cdev() - Returns the I3C device containing @dev 1933a379bbcSBoris Brezillon * @dev: device object 1943a379bbcSBoris Brezillon * 1953a379bbcSBoris Brezillon * Return: a pointer to an I3C device object. 1963a379bbcSBoris Brezillon */ 1973a379bbcSBoris Brezillon struct i3c_device *dev_to_i3cdev(struct device *dev) 1983a379bbcSBoris Brezillon { 1993a379bbcSBoris Brezillon return container_of(dev, struct i3c_device, dev); 2003a379bbcSBoris Brezillon } 2013a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(dev_to_i3cdev); 2023a379bbcSBoris Brezillon 2033a379bbcSBoris Brezillon /** 204934d24a5SVitor Soares * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev 205934d24a5SVitor Soares * @i3cdev: I3C device 206934d24a5SVitor Soares * @id_table: I3C device match table 207934d24a5SVitor Soares * 208934d24a5SVitor Soares * Return: a pointer to an i3c_device_id object or NULL if there's no match. 209934d24a5SVitor Soares */ 210934d24a5SVitor Soares const struct i3c_device_id * 211934d24a5SVitor Soares i3c_device_match_id(struct i3c_device *i3cdev, 212934d24a5SVitor Soares const struct i3c_device_id *id_table) 213934d24a5SVitor Soares { 214934d24a5SVitor Soares struct i3c_device_info devinfo; 215934d24a5SVitor Soares const struct i3c_device_id *id; 216*65ec1d0dSBoris Brezillon u16 manuf, part, ext_info; 217*65ec1d0dSBoris Brezillon bool rndpid; 218934d24a5SVitor Soares 219934d24a5SVitor Soares i3c_device_get_info(i3cdev, &devinfo); 220934d24a5SVitor Soares 221*65ec1d0dSBoris Brezillon manuf = I3C_PID_MANUF_ID(devinfo.pid); 222*65ec1d0dSBoris Brezillon part = I3C_PID_PART_ID(devinfo.pid); 223*65ec1d0dSBoris Brezillon ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); 224*65ec1d0dSBoris Brezillon rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid); 225934d24a5SVitor Soares 226934d24a5SVitor Soares for (id = id_table; id->match_flags != 0; id++) { 227*65ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_DCR) && 228*65ec1d0dSBoris Brezillon id->dcr != devinfo.dcr) 229934d24a5SVitor Soares continue; 230934d24a5SVitor Soares 231*65ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_MANUF) && 232*65ec1d0dSBoris Brezillon id->manuf_id != manuf) 233*65ec1d0dSBoris Brezillon continue; 234*65ec1d0dSBoris Brezillon 235*65ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_PART) && 236*65ec1d0dSBoris Brezillon (rndpid || id->part_id != part)) 237934d24a5SVitor Soares continue; 238934d24a5SVitor Soares 239934d24a5SVitor Soares if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && 240*65ec1d0dSBoris Brezillon (rndpid || id->extra_info != ext_info)) 241934d24a5SVitor Soares continue; 242934d24a5SVitor Soares 243934d24a5SVitor Soares return id; 244934d24a5SVitor Soares } 245934d24a5SVitor Soares 246934d24a5SVitor Soares return NULL; 247934d24a5SVitor Soares } 248934d24a5SVitor Soares EXPORT_SYMBOL_GPL(i3c_device_match_id); 249934d24a5SVitor Soares 250934d24a5SVitor Soares /** 2513a379bbcSBoris Brezillon * i3c_driver_register_with_owner() - register an I3C device driver 2523a379bbcSBoris Brezillon * 2533a379bbcSBoris Brezillon * @drv: driver to register 2543a379bbcSBoris Brezillon * @owner: module that owns this driver 2553a379bbcSBoris Brezillon * 2563a379bbcSBoris Brezillon * Register @drv to the core. 2573a379bbcSBoris Brezillon * 2583a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 2593a379bbcSBoris Brezillon */ 2603a379bbcSBoris Brezillon int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner) 2613a379bbcSBoris Brezillon { 2623a379bbcSBoris Brezillon drv->driver.owner = owner; 2633a379bbcSBoris Brezillon drv->driver.bus = &i3c_bus_type; 2643a379bbcSBoris Brezillon 2653a379bbcSBoris Brezillon return driver_register(&drv->driver); 2663a379bbcSBoris Brezillon } 2673a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner); 2683a379bbcSBoris Brezillon 2693a379bbcSBoris Brezillon /** 2703a379bbcSBoris Brezillon * i3c_driver_unregister() - unregister an I3C device driver 2713a379bbcSBoris Brezillon * 2723a379bbcSBoris Brezillon * @drv: driver to unregister 2733a379bbcSBoris Brezillon * 2743a379bbcSBoris Brezillon * Unregister @drv. 2753a379bbcSBoris Brezillon */ 2763a379bbcSBoris Brezillon void i3c_driver_unregister(struct i3c_driver *drv) 2773a379bbcSBoris Brezillon { 2783a379bbcSBoris Brezillon driver_unregister(&drv->driver); 2793a379bbcSBoris Brezillon } 2803a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_unregister); 281