1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 Cadence Design Systems Inc. 4 * 5 * Author: Boris Brezillon <boris.brezillon@bootlin.com> 6 */ 7 8 #include <linux/atomic.h> 9 #include <linux/bug.h> 10 #include <linux/completion.h> 11 #include <linux/device.h> 12 #include <linux/mutex.h> 13 #include <linux/slab.h> 14 15 #include "internals.h" 16 17 /** 18 * i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a 19 * specific device 20 * 21 * @dev: device with which the transfers should be done 22 * @xfers: array of transfers 23 * @nxfers: number of transfers 24 * 25 * Initiate one or several private SDR transfers with @dev. 26 * 27 * This function can sleep and thus cannot be called in atomic context. 28 * 29 * Return: 0 in case of success, a negative error core otherwise. 30 */ 31 int i3c_device_do_priv_xfers(struct i3c_device *dev, 32 struct i3c_priv_xfer *xfers, 33 int nxfers) 34 { 35 int ret, i; 36 37 if (nxfers < 1) 38 return 0; 39 40 for (i = 0; i < nxfers; i++) { 41 if (!xfers[i].len || !xfers[i].data.in) 42 return -EINVAL; 43 } 44 45 i3c_bus_normaluse_lock(dev->bus); 46 ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers); 47 i3c_bus_normaluse_unlock(dev->bus); 48 49 return ret; 50 } 51 EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers); 52 53 /** 54 * i3c_device_do_setdasa() - do I3C dynamic address assignement with 55 * static address 56 * 57 * @dev: device with which the DAA should be done 58 * 59 * Return: 0 in case of success, a negative error core otherwise. 60 */ 61 int i3c_device_do_setdasa(struct i3c_device *dev) 62 { 63 int ret; 64 65 i3c_bus_normaluse_lock(dev->bus); 66 ret = i3c_dev_setdasa_locked(dev->desc); 67 i3c_bus_normaluse_unlock(dev->bus); 68 69 return ret; 70 } 71 EXPORT_SYMBOL_GPL(i3c_device_do_setdasa); 72 73 /** 74 * i3c_device_get_info() - get I3C device information 75 * 76 * @dev: device we want information on 77 * @info: the information object to fill in 78 * 79 * Retrieve I3C dev info. 80 */ 81 void i3c_device_get_info(struct i3c_device *dev, 82 struct i3c_device_info *info) 83 { 84 if (!info) 85 return; 86 87 i3c_bus_normaluse_lock(dev->bus); 88 if (dev->desc) 89 *info = dev->desc->info; 90 i3c_bus_normaluse_unlock(dev->bus); 91 } 92 EXPORT_SYMBOL_GPL(i3c_device_get_info); 93 94 /** 95 * i3c_device_disable_ibi() - Disable IBIs coming from a specific device 96 * @dev: device on which IBIs should be disabled 97 * 98 * This function disable IBIs coming from a specific device and wait for 99 * all pending IBIs to be processed. 100 * 101 * Return: 0 in case of success, a negative error core otherwise. 102 */ 103 int i3c_device_disable_ibi(struct i3c_device *dev) 104 { 105 int ret = -ENOENT; 106 107 i3c_bus_normaluse_lock(dev->bus); 108 if (dev->desc) { 109 mutex_lock(&dev->desc->ibi_lock); 110 ret = i3c_dev_disable_ibi_locked(dev->desc); 111 mutex_unlock(&dev->desc->ibi_lock); 112 } 113 i3c_bus_normaluse_unlock(dev->bus); 114 115 return ret; 116 } 117 EXPORT_SYMBOL_GPL(i3c_device_disable_ibi); 118 119 /** 120 * i3c_device_enable_ibi() - Enable IBIs coming from a specific device 121 * @dev: device on which IBIs should be enabled 122 * 123 * This function enable IBIs coming from a specific device and wait for 124 * all pending IBIs to be processed. This should be called on a device 125 * where i3c_device_request_ibi() has succeeded. 126 * 127 * Note that IBIs from this device might be received before this function 128 * returns to its caller. 129 * 130 * Return: 0 in case of success, a negative error core otherwise. 131 */ 132 int i3c_device_enable_ibi(struct i3c_device *dev) 133 { 134 int ret = -ENOENT; 135 136 i3c_bus_normaluse_lock(dev->bus); 137 if (dev->desc) { 138 mutex_lock(&dev->desc->ibi_lock); 139 ret = i3c_dev_enable_ibi_locked(dev->desc); 140 mutex_unlock(&dev->desc->ibi_lock); 141 } 142 i3c_bus_normaluse_unlock(dev->bus); 143 144 return ret; 145 } 146 EXPORT_SYMBOL_GPL(i3c_device_enable_ibi); 147 148 /** 149 * i3c_device_request_ibi() - Request an IBI 150 * @dev: device for which we should enable IBIs 151 * @req: setup requested for this IBI 152 * 153 * This function is responsible for pre-allocating all resources needed to 154 * process IBIs coming from @dev. When this function returns, the IBI is not 155 * enabled until i3c_device_enable_ibi() is called. 156 * 157 * Return: 0 in case of success, a negative error core otherwise. 158 */ 159 int i3c_device_request_ibi(struct i3c_device *dev, 160 const struct i3c_ibi_setup *req) 161 { 162 int ret = -ENOENT; 163 164 if (!req->handler || !req->num_slots) 165 return -EINVAL; 166 167 i3c_bus_normaluse_lock(dev->bus); 168 if (dev->desc) { 169 mutex_lock(&dev->desc->ibi_lock); 170 ret = i3c_dev_request_ibi_locked(dev->desc, req); 171 mutex_unlock(&dev->desc->ibi_lock); 172 } 173 i3c_bus_normaluse_unlock(dev->bus); 174 175 return ret; 176 } 177 EXPORT_SYMBOL_GPL(i3c_device_request_ibi); 178 179 /** 180 * i3c_device_free_ibi() - Free all resources needed for IBI handling 181 * @dev: device on which you want to release IBI resources 182 * 183 * This function is responsible for de-allocating resources previously 184 * allocated by i3c_device_request_ibi(). It should be called after disabling 185 * IBIs with i3c_device_disable_ibi(). 186 */ 187 void i3c_device_free_ibi(struct i3c_device *dev) 188 { 189 i3c_bus_normaluse_lock(dev->bus); 190 if (dev->desc) { 191 mutex_lock(&dev->desc->ibi_lock); 192 i3c_dev_free_ibi_locked(dev->desc); 193 mutex_unlock(&dev->desc->ibi_lock); 194 } 195 i3c_bus_normaluse_unlock(dev->bus); 196 } 197 EXPORT_SYMBOL_GPL(i3c_device_free_ibi); 198 199 /** 200 * i3cdev_to_dev() - Returns the device embedded in @i3cdev 201 * @i3cdev: I3C device 202 * 203 * Return: a pointer to a device object. 204 */ 205 struct device *i3cdev_to_dev(struct i3c_device *i3cdev) 206 { 207 return &i3cdev->dev; 208 } 209 EXPORT_SYMBOL_GPL(i3cdev_to_dev); 210 211 /** 212 * dev_to_i3cdev() - Returns the I3C device containing @dev 213 * @dev: device object 214 * 215 * Return: a pointer to an I3C device object. 216 */ 217 struct i3c_device *dev_to_i3cdev(struct device *dev) 218 { 219 return container_of(dev, struct i3c_device, dev); 220 } 221 EXPORT_SYMBOL_GPL(dev_to_i3cdev); 222 223 /** 224 * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev 225 * @i3cdev: I3C device 226 * @id_table: I3C device match table 227 * 228 * Return: a pointer to an i3c_device_id object or NULL if there's no match. 229 */ 230 const struct i3c_device_id * 231 i3c_device_match_id(struct i3c_device *i3cdev, 232 const struct i3c_device_id *id_table) 233 { 234 struct i3c_device_info devinfo; 235 const struct i3c_device_id *id; 236 u16 manuf, part, ext_info; 237 bool rndpid; 238 239 i3c_device_get_info(i3cdev, &devinfo); 240 241 manuf = I3C_PID_MANUF_ID(devinfo.pid); 242 part = I3C_PID_PART_ID(devinfo.pid); 243 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); 244 rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid); 245 246 for (id = id_table; id->match_flags != 0; id++) { 247 if ((id->match_flags & I3C_MATCH_DCR) && 248 id->dcr != devinfo.dcr) 249 continue; 250 251 if ((id->match_flags & I3C_MATCH_MANUF) && 252 id->manuf_id != manuf) 253 continue; 254 255 if ((id->match_flags & I3C_MATCH_PART) && 256 (rndpid || id->part_id != part)) 257 continue; 258 259 if ((id->match_flags & I3C_MATCH_EXTRA_INFO) && 260 (rndpid || id->extra_info != ext_info)) 261 continue; 262 263 return id; 264 } 265 266 return NULL; 267 } 268 EXPORT_SYMBOL_GPL(i3c_device_match_id); 269 270 /** 271 * i3c_driver_register_with_owner() - register an I3C device driver 272 * 273 * @drv: driver to register 274 * @owner: module that owns this driver 275 * 276 * Register @drv to the core. 277 * 278 * Return: 0 in case of success, a negative error core otherwise. 279 */ 280 int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner) 281 { 282 drv->driver.owner = owner; 283 drv->driver.bus = &i3c_bus_type; 284 285 if (!drv->probe) { 286 pr_err("Trying to register an i3c driver without probe callback\n"); 287 return -EINVAL; 288 } 289 290 return driver_register(&drv->driver); 291 } 292 EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner); 293 294 /** 295 * i3c_driver_unregister() - unregister an I3C device driver 296 * 297 * @drv: driver to unregister 298 * 299 * Unregister @drv. 300 */ 301 void i3c_driver_unregister(struct i3c_driver *drv) 302 { 303 driver_unregister(&drv->driver); 304 } 305 EXPORT_SYMBOL_GPL(i3c_driver_unregister); 306