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 /** 54*672825cdSJack Chen * i3c_device_do_setdasa() - do I3C dynamic address assignement with 55*672825cdSJack Chen * static address 56*672825cdSJack Chen * 57*672825cdSJack Chen * @dev: device with which the DAA should be done 58*672825cdSJack Chen * 59*672825cdSJack Chen * Return: 0 in case of success, a negative error core otherwise. 60*672825cdSJack Chen */ 61*672825cdSJack Chen int i3c_device_do_setdasa(struct i3c_device *dev) 62*672825cdSJack Chen { 63*672825cdSJack Chen int ret; 64*672825cdSJack Chen 65*672825cdSJack Chen i3c_bus_normaluse_lock(dev->bus); 66*672825cdSJack Chen ret = i3c_dev_setdasa_locked(dev->desc); 67*672825cdSJack Chen i3c_bus_normaluse_unlock(dev->bus); 68*672825cdSJack Chen 69*672825cdSJack Chen return ret; 70*672825cdSJack Chen } 71*672825cdSJack Chen EXPORT_SYMBOL_GPL(i3c_device_do_setdasa); 72*672825cdSJack Chen 73*672825cdSJack Chen /** 743a379bbcSBoris Brezillon * i3c_device_get_info() - get I3C device information 753a379bbcSBoris Brezillon * 763a379bbcSBoris Brezillon * @dev: device we want information on 773a379bbcSBoris Brezillon * @info: the information object to fill in 783a379bbcSBoris Brezillon * 793a379bbcSBoris Brezillon * Retrieve I3C dev info. 803a379bbcSBoris Brezillon */ 813a379bbcSBoris Brezillon void i3c_device_get_info(struct i3c_device *dev, 823a379bbcSBoris Brezillon struct i3c_device_info *info) 833a379bbcSBoris Brezillon { 843a379bbcSBoris Brezillon if (!info) 853a379bbcSBoris Brezillon return; 863a379bbcSBoris Brezillon 873a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 883a379bbcSBoris Brezillon if (dev->desc) 893a379bbcSBoris Brezillon *info = dev->desc->info; 903a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 913a379bbcSBoris Brezillon } 923a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_get_info); 933a379bbcSBoris Brezillon 943a379bbcSBoris Brezillon /** 953a379bbcSBoris Brezillon * i3c_device_disable_ibi() - Disable IBIs coming from a specific device 963a379bbcSBoris Brezillon * @dev: device on which IBIs should be disabled 973a379bbcSBoris Brezillon * 983a379bbcSBoris Brezillon * This function disable IBIs coming from a specific device and wait for 993a379bbcSBoris Brezillon * all pending IBIs to be processed. 1003a379bbcSBoris Brezillon * 1013a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1023a379bbcSBoris Brezillon */ 1033a379bbcSBoris Brezillon int i3c_device_disable_ibi(struct i3c_device *dev) 1043a379bbcSBoris Brezillon { 1053a379bbcSBoris Brezillon int ret = -ENOENT; 1063a379bbcSBoris Brezillon 1073a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1083a379bbcSBoris Brezillon if (dev->desc) { 1093a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1103a379bbcSBoris Brezillon ret = i3c_dev_disable_ibi_locked(dev->desc); 1113a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1123a379bbcSBoris Brezillon } 1133a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1143a379bbcSBoris Brezillon 1153a379bbcSBoris Brezillon return ret; 1163a379bbcSBoris Brezillon } 1173a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_disable_ibi); 1183a379bbcSBoris Brezillon 1193a379bbcSBoris Brezillon /** 1203a379bbcSBoris Brezillon * i3c_device_enable_ibi() - Enable IBIs coming from a specific device 1213a379bbcSBoris Brezillon * @dev: device on which IBIs should be enabled 1223a379bbcSBoris Brezillon * 1233a379bbcSBoris Brezillon * This function enable IBIs coming from a specific device and wait for 1243a379bbcSBoris Brezillon * all pending IBIs to be processed. This should be called on a device 1253a379bbcSBoris Brezillon * where i3c_device_request_ibi() has succeeded. 1263a379bbcSBoris Brezillon * 1273a379bbcSBoris Brezillon * Note that IBIs from this device might be received before this function 1283a379bbcSBoris Brezillon * returns to its caller. 1293a379bbcSBoris Brezillon * 1303a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1313a379bbcSBoris Brezillon */ 1323a379bbcSBoris Brezillon int i3c_device_enable_ibi(struct i3c_device *dev) 1333a379bbcSBoris Brezillon { 1343a379bbcSBoris Brezillon int ret = -ENOENT; 1353a379bbcSBoris Brezillon 1363a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1373a379bbcSBoris Brezillon if (dev->desc) { 1383a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1393a379bbcSBoris Brezillon ret = i3c_dev_enable_ibi_locked(dev->desc); 1403a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1413a379bbcSBoris Brezillon } 1423a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1433a379bbcSBoris Brezillon 1443a379bbcSBoris Brezillon return ret; 1453a379bbcSBoris Brezillon } 1463a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_enable_ibi); 1473a379bbcSBoris Brezillon 1483a379bbcSBoris Brezillon /** 1493a379bbcSBoris Brezillon * i3c_device_request_ibi() - Request an IBI 1503a379bbcSBoris Brezillon * @dev: device for which we should enable IBIs 1513a379bbcSBoris Brezillon * @req: setup requested for this IBI 1523a379bbcSBoris Brezillon * 1533a379bbcSBoris Brezillon * This function is responsible for pre-allocating all resources needed to 1543a379bbcSBoris Brezillon * process IBIs coming from @dev. When this function returns, the IBI is not 1553a379bbcSBoris Brezillon * enabled until i3c_device_enable_ibi() is called. 1563a379bbcSBoris Brezillon * 1573a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1583a379bbcSBoris Brezillon */ 1593a379bbcSBoris Brezillon int i3c_device_request_ibi(struct i3c_device *dev, 1603a379bbcSBoris Brezillon const struct i3c_ibi_setup *req) 1613a379bbcSBoris Brezillon { 1623a379bbcSBoris Brezillon int ret = -ENOENT; 1633a379bbcSBoris Brezillon 1643a379bbcSBoris Brezillon if (!req->handler || !req->num_slots) 1653a379bbcSBoris Brezillon return -EINVAL; 1663a379bbcSBoris Brezillon 1673a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1683a379bbcSBoris Brezillon if (dev->desc) { 1693a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1703a379bbcSBoris Brezillon ret = i3c_dev_request_ibi_locked(dev->desc, req); 1713a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1723a379bbcSBoris Brezillon } 1733a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1743a379bbcSBoris Brezillon 1753a379bbcSBoris Brezillon return ret; 1763a379bbcSBoris Brezillon } 1773a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_request_ibi); 1783a379bbcSBoris Brezillon 1793a379bbcSBoris Brezillon /** 1803a379bbcSBoris Brezillon * i3c_device_free_ibi() - Free all resources needed for IBI handling 1813a379bbcSBoris Brezillon * @dev: device on which you want to release IBI resources 1823a379bbcSBoris Brezillon * 1833a379bbcSBoris Brezillon * This function is responsible for de-allocating resources previously 1843a379bbcSBoris Brezillon * allocated by i3c_device_request_ibi(). It should be called after disabling 1853a379bbcSBoris Brezillon * IBIs with i3c_device_disable_ibi(). 1863a379bbcSBoris Brezillon */ 1873a379bbcSBoris Brezillon void i3c_device_free_ibi(struct i3c_device *dev) 1883a379bbcSBoris Brezillon { 1893a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1903a379bbcSBoris Brezillon if (dev->desc) { 1913a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1923a379bbcSBoris Brezillon i3c_dev_free_ibi_locked(dev->desc); 1933a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1943a379bbcSBoris Brezillon } 1953a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1963a379bbcSBoris Brezillon } 1973a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_free_ibi); 1983a379bbcSBoris Brezillon 1993a379bbcSBoris Brezillon /** 2003a379bbcSBoris Brezillon * i3cdev_to_dev() - Returns the device embedded in @i3cdev 2013a379bbcSBoris Brezillon * @i3cdev: I3C device 2023a379bbcSBoris Brezillon * 2033a379bbcSBoris Brezillon * Return: a pointer to a device object. 2043a379bbcSBoris Brezillon */ 2053a379bbcSBoris Brezillon struct device *i3cdev_to_dev(struct i3c_device *i3cdev) 2063a379bbcSBoris Brezillon { 2073a379bbcSBoris Brezillon return &i3cdev->dev; 2083a379bbcSBoris Brezillon } 2093a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3cdev_to_dev); 2103a379bbcSBoris Brezillon 2113a379bbcSBoris Brezillon /** 2123a379bbcSBoris Brezillon * dev_to_i3cdev() - Returns the I3C device containing @dev 2133a379bbcSBoris Brezillon * @dev: device object 2143a379bbcSBoris Brezillon * 2153a379bbcSBoris Brezillon * Return: a pointer to an I3C device object. 2163a379bbcSBoris Brezillon */ 2173a379bbcSBoris Brezillon struct i3c_device *dev_to_i3cdev(struct device *dev) 2183a379bbcSBoris Brezillon { 2193a379bbcSBoris Brezillon return container_of(dev, struct i3c_device, dev); 2203a379bbcSBoris Brezillon } 2213a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(dev_to_i3cdev); 2223a379bbcSBoris Brezillon 2233a379bbcSBoris Brezillon /** 224934d24a5SVitor Soares * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev 225934d24a5SVitor Soares * @i3cdev: I3C device 226934d24a5SVitor Soares * @id_table: I3C device match table 227934d24a5SVitor Soares * 228934d24a5SVitor Soares * Return: a pointer to an i3c_device_id object or NULL if there's no match. 229934d24a5SVitor Soares */ 230934d24a5SVitor Soares const struct i3c_device_id * 231934d24a5SVitor Soares i3c_device_match_id(struct i3c_device *i3cdev, 232934d24a5SVitor Soares const struct i3c_device_id *id_table) 233934d24a5SVitor Soares { 234934d24a5SVitor Soares struct i3c_device_info devinfo; 235934d24a5SVitor Soares const struct i3c_device_id *id; 23665ec1d0dSBoris Brezillon u16 manuf, part, ext_info; 23765ec1d0dSBoris Brezillon bool rndpid; 238934d24a5SVitor Soares 239934d24a5SVitor Soares i3c_device_get_info(i3cdev, &devinfo); 240934d24a5SVitor Soares 24165ec1d0dSBoris Brezillon manuf = I3C_PID_MANUF_ID(devinfo.pid); 24265ec1d0dSBoris Brezillon part = I3C_PID_PART_ID(devinfo.pid); 24365ec1d0dSBoris Brezillon ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); 24465ec1d0dSBoris Brezillon rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid); 245934d24a5SVitor Soares 246934d24a5SVitor Soares for (id = id_table; id->match_flags != 0; id++) { 24765ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_DCR) && 24865ec1d0dSBoris Brezillon id->dcr != devinfo.dcr) 249934d24a5SVitor Soares continue; 250934d24a5SVitor Soares 25165ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_MANUF) && 25265ec1d0dSBoris Brezillon id->manuf_id != manuf) 25365ec1d0dSBoris Brezillon continue; 25465ec1d0dSBoris Brezillon 25565ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_PART) && 25665ec1d0dSBoris Brezillon (rndpid || id->part_id != part)) 257934d24a5SVitor Soares continue; 258934d24a5SVitor Soares 259934d24a5SVitor Soares if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && 26065ec1d0dSBoris Brezillon (rndpid || id->extra_info != ext_info)) 261934d24a5SVitor Soares continue; 262934d24a5SVitor Soares 263934d24a5SVitor Soares return id; 264934d24a5SVitor Soares } 265934d24a5SVitor Soares 266934d24a5SVitor Soares return NULL; 267934d24a5SVitor Soares } 268934d24a5SVitor Soares EXPORT_SYMBOL_GPL(i3c_device_match_id); 269934d24a5SVitor Soares 270934d24a5SVitor Soares /** 2713a379bbcSBoris Brezillon * i3c_driver_register_with_owner() - register an I3C device driver 2723a379bbcSBoris Brezillon * 2733a379bbcSBoris Brezillon * @drv: driver to register 2743a379bbcSBoris Brezillon * @owner: module that owns this driver 2753a379bbcSBoris Brezillon * 2763a379bbcSBoris Brezillon * Register @drv to the core. 2773a379bbcSBoris Brezillon * 2783a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 2793a379bbcSBoris Brezillon */ 2803a379bbcSBoris Brezillon int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner) 2813a379bbcSBoris Brezillon { 2823a379bbcSBoris Brezillon drv->driver.owner = owner; 2833a379bbcSBoris Brezillon drv->driver.bus = &i3c_bus_type; 2843a379bbcSBoris Brezillon 2857456fea5SUwe Kleine-König if (!drv->probe) { 2867456fea5SUwe Kleine-König pr_err("Trying to register an i3c driver without probe callback\n"); 2877456fea5SUwe Kleine-König return -EINVAL; 2887456fea5SUwe Kleine-König } 2897456fea5SUwe Kleine-König 2903a379bbcSBoris Brezillon return driver_register(&drv->driver); 2913a379bbcSBoris Brezillon } 2923a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner); 2933a379bbcSBoris Brezillon 2943a379bbcSBoris Brezillon /** 2953a379bbcSBoris Brezillon * i3c_driver_unregister() - unregister an I3C device driver 2963a379bbcSBoris Brezillon * 2973a379bbcSBoris Brezillon * @drv: driver to unregister 2983a379bbcSBoris Brezillon * 2993a379bbcSBoris Brezillon * Unregister @drv. 3003a379bbcSBoris Brezillon */ 3013a379bbcSBoris Brezillon void i3c_driver_unregister(struct i3c_driver *drv) 3023a379bbcSBoris Brezillon { 3033a379bbcSBoris Brezillon driver_unregister(&drv->driver); 3043a379bbcSBoris Brezillon } 3053a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_unregister); 306