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. 30*0d259650SFrank Li * -EAGAIN: controller lost address arbitration. Target 31*0d259650SFrank Li * (IBI, HJ or controller role request) win the bus. Client 32*0d259650SFrank Li * driver needs to resend the 'xfers' some time later. 33*0d259650SFrank Li * See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3. 343a379bbcSBoris Brezillon */ 353a379bbcSBoris Brezillon int i3c_device_do_priv_xfers(struct i3c_device *dev, 363a379bbcSBoris Brezillon struct i3c_priv_xfer *xfers, 373a379bbcSBoris Brezillon int nxfers) 383a379bbcSBoris Brezillon { 393a379bbcSBoris Brezillon int ret, i; 403a379bbcSBoris Brezillon 413a379bbcSBoris Brezillon if (nxfers < 1) 423a379bbcSBoris Brezillon return 0; 433a379bbcSBoris Brezillon 443a379bbcSBoris Brezillon for (i = 0; i < nxfers; i++) { 453a379bbcSBoris Brezillon if (!xfers[i].len || !xfers[i].data.in) 463a379bbcSBoris Brezillon return -EINVAL; 473a379bbcSBoris Brezillon } 483a379bbcSBoris Brezillon 493a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 503a379bbcSBoris Brezillon ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers); 513a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 523a379bbcSBoris Brezillon 533a379bbcSBoris Brezillon return ret; 543a379bbcSBoris Brezillon } 553a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers); 563a379bbcSBoris Brezillon 573a379bbcSBoris Brezillon /** 58672825cdSJack Chen * i3c_device_do_setdasa() - do I3C dynamic address assignement with 59672825cdSJack Chen * static address 60672825cdSJack Chen * 61672825cdSJack Chen * @dev: device with which the DAA should be done 62672825cdSJack Chen * 63672825cdSJack Chen * Return: 0 in case of success, a negative error core otherwise. 64672825cdSJack Chen */ 65672825cdSJack Chen int i3c_device_do_setdasa(struct i3c_device *dev) 66672825cdSJack Chen { 67672825cdSJack Chen int ret; 68672825cdSJack Chen 69672825cdSJack Chen i3c_bus_normaluse_lock(dev->bus); 70672825cdSJack Chen ret = i3c_dev_setdasa_locked(dev->desc); 71672825cdSJack Chen i3c_bus_normaluse_unlock(dev->bus); 72672825cdSJack Chen 73672825cdSJack Chen return ret; 74672825cdSJack Chen } 75672825cdSJack Chen EXPORT_SYMBOL_GPL(i3c_device_do_setdasa); 76672825cdSJack Chen 77672825cdSJack Chen /** 783a379bbcSBoris Brezillon * i3c_device_get_info() - get I3C device information 793a379bbcSBoris Brezillon * 803a379bbcSBoris Brezillon * @dev: device we want information on 813a379bbcSBoris Brezillon * @info: the information object to fill in 823a379bbcSBoris Brezillon * 833a379bbcSBoris Brezillon * Retrieve I3C dev info. 843a379bbcSBoris Brezillon */ 85162736b0SGreg Kroah-Hartman void i3c_device_get_info(const struct i3c_device *dev, 863a379bbcSBoris Brezillon struct i3c_device_info *info) 873a379bbcSBoris Brezillon { 883a379bbcSBoris Brezillon if (!info) 893a379bbcSBoris Brezillon return; 903a379bbcSBoris Brezillon 913a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 923a379bbcSBoris Brezillon if (dev->desc) 933a379bbcSBoris Brezillon *info = dev->desc->info; 943a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 953a379bbcSBoris Brezillon } 963a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_get_info); 973a379bbcSBoris Brezillon 983a379bbcSBoris Brezillon /** 993a379bbcSBoris Brezillon * i3c_device_disable_ibi() - Disable IBIs coming from a specific device 1003a379bbcSBoris Brezillon * @dev: device on which IBIs should be disabled 1013a379bbcSBoris Brezillon * 1023a379bbcSBoris Brezillon * This function disable IBIs coming from a specific device and wait for 1033a379bbcSBoris Brezillon * all pending IBIs to be processed. 1043a379bbcSBoris Brezillon * 1053a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1063a379bbcSBoris Brezillon */ 1073a379bbcSBoris Brezillon int i3c_device_disable_ibi(struct i3c_device *dev) 1083a379bbcSBoris Brezillon { 1093a379bbcSBoris Brezillon int ret = -ENOENT; 1103a379bbcSBoris Brezillon 1113a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1123a379bbcSBoris Brezillon if (dev->desc) { 1133a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1143a379bbcSBoris Brezillon ret = i3c_dev_disable_ibi_locked(dev->desc); 1153a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1163a379bbcSBoris Brezillon } 1173a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1183a379bbcSBoris Brezillon 1193a379bbcSBoris Brezillon return ret; 1203a379bbcSBoris Brezillon } 1213a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_disable_ibi); 1223a379bbcSBoris Brezillon 1233a379bbcSBoris Brezillon /** 1243a379bbcSBoris Brezillon * i3c_device_enable_ibi() - Enable IBIs coming from a specific device 1253a379bbcSBoris Brezillon * @dev: device on which IBIs should be enabled 1263a379bbcSBoris Brezillon * 1273a379bbcSBoris Brezillon * This function enable IBIs coming from a specific device and wait for 1283a379bbcSBoris Brezillon * all pending IBIs to be processed. This should be called on a device 1293a379bbcSBoris Brezillon * where i3c_device_request_ibi() has succeeded. 1303a379bbcSBoris Brezillon * 1313a379bbcSBoris Brezillon * Note that IBIs from this device might be received before this function 1323a379bbcSBoris Brezillon * returns to its caller. 1333a379bbcSBoris Brezillon * 1343a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1353a379bbcSBoris Brezillon */ 1363a379bbcSBoris Brezillon int i3c_device_enable_ibi(struct i3c_device *dev) 1373a379bbcSBoris Brezillon { 1383a379bbcSBoris Brezillon int ret = -ENOENT; 1393a379bbcSBoris Brezillon 1403a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1413a379bbcSBoris Brezillon if (dev->desc) { 1423a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1433a379bbcSBoris Brezillon ret = i3c_dev_enable_ibi_locked(dev->desc); 1443a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1453a379bbcSBoris Brezillon } 1463a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1473a379bbcSBoris Brezillon 1483a379bbcSBoris Brezillon return ret; 1493a379bbcSBoris Brezillon } 1503a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_enable_ibi); 1513a379bbcSBoris Brezillon 1523a379bbcSBoris Brezillon /** 1533a379bbcSBoris Brezillon * i3c_device_request_ibi() - Request an IBI 1543a379bbcSBoris Brezillon * @dev: device for which we should enable IBIs 1553a379bbcSBoris Brezillon * @req: setup requested for this IBI 1563a379bbcSBoris Brezillon * 1573a379bbcSBoris Brezillon * This function is responsible for pre-allocating all resources needed to 1583a379bbcSBoris Brezillon * process IBIs coming from @dev. When this function returns, the IBI is not 1593a379bbcSBoris Brezillon * enabled until i3c_device_enable_ibi() is called. 1603a379bbcSBoris Brezillon * 1613a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 1623a379bbcSBoris Brezillon */ 1633a379bbcSBoris Brezillon int i3c_device_request_ibi(struct i3c_device *dev, 1643a379bbcSBoris Brezillon const struct i3c_ibi_setup *req) 1653a379bbcSBoris Brezillon { 1663a379bbcSBoris Brezillon int ret = -ENOENT; 1673a379bbcSBoris Brezillon 1683a379bbcSBoris Brezillon if (!req->handler || !req->num_slots) 1693a379bbcSBoris Brezillon return -EINVAL; 1703a379bbcSBoris Brezillon 1713a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1723a379bbcSBoris Brezillon if (dev->desc) { 1733a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1743a379bbcSBoris Brezillon ret = i3c_dev_request_ibi_locked(dev->desc, req); 1753a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1763a379bbcSBoris Brezillon } 1773a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 1783a379bbcSBoris Brezillon 1793a379bbcSBoris Brezillon return ret; 1803a379bbcSBoris Brezillon } 1813a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_request_ibi); 1823a379bbcSBoris Brezillon 1833a379bbcSBoris Brezillon /** 1843a379bbcSBoris Brezillon * i3c_device_free_ibi() - Free all resources needed for IBI handling 1853a379bbcSBoris Brezillon * @dev: device on which you want to release IBI resources 1863a379bbcSBoris Brezillon * 1873a379bbcSBoris Brezillon * This function is responsible for de-allocating resources previously 1883a379bbcSBoris Brezillon * allocated by i3c_device_request_ibi(). It should be called after disabling 1893a379bbcSBoris Brezillon * IBIs with i3c_device_disable_ibi(). 1903a379bbcSBoris Brezillon */ 1913a379bbcSBoris Brezillon void i3c_device_free_ibi(struct i3c_device *dev) 1923a379bbcSBoris Brezillon { 1933a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 1943a379bbcSBoris Brezillon if (dev->desc) { 1953a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 1963a379bbcSBoris Brezillon i3c_dev_free_ibi_locked(dev->desc); 1973a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 1983a379bbcSBoris Brezillon } 1993a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 2003a379bbcSBoris Brezillon } 2013a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_free_ibi); 2023a379bbcSBoris Brezillon 2033a379bbcSBoris Brezillon /** 2043a379bbcSBoris Brezillon * i3cdev_to_dev() - Returns the device embedded in @i3cdev 2053a379bbcSBoris Brezillon * @i3cdev: I3C device 2063a379bbcSBoris Brezillon * 2073a379bbcSBoris Brezillon * Return: a pointer to a device object. 2083a379bbcSBoris Brezillon */ 2093a379bbcSBoris Brezillon struct device *i3cdev_to_dev(struct i3c_device *i3cdev) 2103a379bbcSBoris Brezillon { 2113a379bbcSBoris Brezillon return &i3cdev->dev; 2123a379bbcSBoris Brezillon } 2133a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3cdev_to_dev); 2143a379bbcSBoris Brezillon 2153a379bbcSBoris Brezillon /** 216934d24a5SVitor Soares * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev 217934d24a5SVitor Soares * @i3cdev: I3C device 218934d24a5SVitor Soares * @id_table: I3C device match table 219934d24a5SVitor Soares * 220934d24a5SVitor Soares * Return: a pointer to an i3c_device_id object or NULL if there's no match. 221934d24a5SVitor Soares */ 222934d24a5SVitor Soares const struct i3c_device_id * 223934d24a5SVitor Soares i3c_device_match_id(struct i3c_device *i3cdev, 224934d24a5SVitor Soares const struct i3c_device_id *id_table) 225934d24a5SVitor Soares { 226934d24a5SVitor Soares struct i3c_device_info devinfo; 227934d24a5SVitor Soares const struct i3c_device_id *id; 22865ec1d0dSBoris Brezillon u16 manuf, part, ext_info; 22965ec1d0dSBoris Brezillon bool rndpid; 230934d24a5SVitor Soares 231934d24a5SVitor Soares i3c_device_get_info(i3cdev, &devinfo); 232934d24a5SVitor Soares 23365ec1d0dSBoris Brezillon manuf = I3C_PID_MANUF_ID(devinfo.pid); 23465ec1d0dSBoris Brezillon part = I3C_PID_PART_ID(devinfo.pid); 23565ec1d0dSBoris Brezillon ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); 23665ec1d0dSBoris Brezillon rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid); 237934d24a5SVitor Soares 238934d24a5SVitor Soares for (id = id_table; id->match_flags != 0; id++) { 23965ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_DCR) && 24065ec1d0dSBoris Brezillon id->dcr != devinfo.dcr) 241934d24a5SVitor Soares continue; 242934d24a5SVitor Soares 24365ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_MANUF) && 24465ec1d0dSBoris Brezillon id->manuf_id != manuf) 24565ec1d0dSBoris Brezillon continue; 24665ec1d0dSBoris Brezillon 24765ec1d0dSBoris Brezillon if ((id->match_flags & I3C_MATCH_PART) && 24865ec1d0dSBoris Brezillon (rndpid || id->part_id != part)) 249934d24a5SVitor Soares continue; 250934d24a5SVitor Soares 251934d24a5SVitor Soares if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && 25265ec1d0dSBoris Brezillon (rndpid || id->extra_info != ext_info)) 253934d24a5SVitor Soares continue; 254934d24a5SVitor Soares 255934d24a5SVitor Soares return id; 256934d24a5SVitor Soares } 257934d24a5SVitor Soares 258934d24a5SVitor Soares return NULL; 259934d24a5SVitor Soares } 260934d24a5SVitor Soares EXPORT_SYMBOL_GPL(i3c_device_match_id); 261934d24a5SVitor Soares 262934d24a5SVitor Soares /** 2633a379bbcSBoris Brezillon * i3c_driver_register_with_owner() - register an I3C device driver 2643a379bbcSBoris Brezillon * 2653a379bbcSBoris Brezillon * @drv: driver to register 2663a379bbcSBoris Brezillon * @owner: module that owns this driver 2673a379bbcSBoris Brezillon * 2683a379bbcSBoris Brezillon * Register @drv to the core. 2693a379bbcSBoris Brezillon * 2703a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 2713a379bbcSBoris Brezillon */ 2723a379bbcSBoris Brezillon int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner) 2733a379bbcSBoris Brezillon { 2743a379bbcSBoris Brezillon drv->driver.owner = owner; 2753a379bbcSBoris Brezillon drv->driver.bus = &i3c_bus_type; 2763a379bbcSBoris Brezillon 2777456fea5SUwe Kleine-König if (!drv->probe) { 2787456fea5SUwe Kleine-König pr_err("Trying to register an i3c driver without probe callback\n"); 2797456fea5SUwe Kleine-König return -EINVAL; 2807456fea5SUwe Kleine-König } 2817456fea5SUwe Kleine-König 2823a379bbcSBoris Brezillon return driver_register(&drv->driver); 2833a379bbcSBoris Brezillon } 2843a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner); 2853a379bbcSBoris Brezillon 2863a379bbcSBoris Brezillon /** 2873a379bbcSBoris Brezillon * i3c_driver_unregister() - unregister an I3C device driver 2883a379bbcSBoris Brezillon * 2893a379bbcSBoris Brezillon * @drv: driver to unregister 2903a379bbcSBoris Brezillon * 2913a379bbcSBoris Brezillon * Unregister @drv. 2923a379bbcSBoris Brezillon */ 2933a379bbcSBoris Brezillon void i3c_driver_unregister(struct i3c_driver *drv) 2943a379bbcSBoris Brezillon { 2953a379bbcSBoris Brezillon driver_unregister(&drv->driver); 2963a379bbcSBoris Brezillon } 2973a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_unregister); 298