root/drivers/i3c/device.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. i3c_device_do_priv_xfers
  2. i3c_device_get_info
  3. i3c_device_disable_ibi
  4. i3c_device_enable_ibi
  5. i3c_device_request_ibi
  6. i3c_device_free_ibi
  7. i3cdev_to_dev
  8. dev_to_i3cdev
  9. i3c_device_match_id
  10. i3c_driver_register_with_owner
  11. i3c_driver_unregister

   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_get_info() - get I3C device information
  55  *
  56  * @dev: device we want information on
  57  * @info: the information object to fill in
  58  *
  59  * Retrieve I3C dev info.
  60  */
  61 void i3c_device_get_info(struct i3c_device *dev,
  62                          struct i3c_device_info *info)
  63 {
  64         if (!info)
  65                 return;
  66 
  67         i3c_bus_normaluse_lock(dev->bus);
  68         if (dev->desc)
  69                 *info = dev->desc->info;
  70         i3c_bus_normaluse_unlock(dev->bus);
  71 }
  72 EXPORT_SYMBOL_GPL(i3c_device_get_info);
  73 
  74 /**
  75  * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
  76  * @dev: device on which IBIs should be disabled
  77  *
  78  * This function disable IBIs coming from a specific device and wait for
  79  * all pending IBIs to be processed.
  80  *
  81  * Return: 0 in case of success, a negative error core otherwise.
  82  */
  83 int i3c_device_disable_ibi(struct i3c_device *dev)
  84 {
  85         int ret = -ENOENT;
  86 
  87         i3c_bus_normaluse_lock(dev->bus);
  88         if (dev->desc) {
  89                 mutex_lock(&dev->desc->ibi_lock);
  90                 ret = i3c_dev_disable_ibi_locked(dev->desc);
  91                 mutex_unlock(&dev->desc->ibi_lock);
  92         }
  93         i3c_bus_normaluse_unlock(dev->bus);
  94 
  95         return ret;
  96 }
  97 EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
  98 
  99 /**
 100  * i3c_device_enable_ibi() - Enable IBIs coming from a specific device
 101  * @dev: device on which IBIs should be enabled
 102  *
 103  * This function enable IBIs coming from a specific device and wait for
 104  * all pending IBIs to be processed. This should be called on a device
 105  * where i3c_device_request_ibi() has succeeded.
 106  *
 107  * Note that IBIs from this device might be received before this function
 108  * returns to its caller.
 109  *
 110  * Return: 0 in case of success, a negative error core otherwise.
 111  */
 112 int i3c_device_enable_ibi(struct i3c_device *dev)
 113 {
 114         int ret = -ENOENT;
 115 
 116         i3c_bus_normaluse_lock(dev->bus);
 117         if (dev->desc) {
 118                 mutex_lock(&dev->desc->ibi_lock);
 119                 ret = i3c_dev_enable_ibi_locked(dev->desc);
 120                 mutex_unlock(&dev->desc->ibi_lock);
 121         }
 122         i3c_bus_normaluse_unlock(dev->bus);
 123 
 124         return ret;
 125 }
 126 EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
 127 
 128 /**
 129  * i3c_device_request_ibi() - Request an IBI
 130  * @dev: device for which we should enable IBIs
 131  * @req: setup requested for this IBI
 132  *
 133  * This function is responsible for pre-allocating all resources needed to
 134  * process IBIs coming from @dev. When this function returns, the IBI is not
 135  * enabled until i3c_device_enable_ibi() is called.
 136  *
 137  * Return: 0 in case of success, a negative error core otherwise.
 138  */
 139 int i3c_device_request_ibi(struct i3c_device *dev,
 140                            const struct i3c_ibi_setup *req)
 141 {
 142         int ret = -ENOENT;
 143 
 144         if (!req->handler || !req->num_slots)
 145                 return -EINVAL;
 146 
 147         i3c_bus_normaluse_lock(dev->bus);
 148         if (dev->desc) {
 149                 mutex_lock(&dev->desc->ibi_lock);
 150                 ret = i3c_dev_request_ibi_locked(dev->desc, req);
 151                 mutex_unlock(&dev->desc->ibi_lock);
 152         }
 153         i3c_bus_normaluse_unlock(dev->bus);
 154 
 155         return ret;
 156 }
 157 EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
 158 
 159 /**
 160  * i3c_device_free_ibi() - Free all resources needed for IBI handling
 161  * @dev: device on which you want to release IBI resources
 162  *
 163  * This function is responsible for de-allocating resources previously
 164  * allocated by i3c_device_request_ibi(). It should be called after disabling
 165  * IBIs with i3c_device_disable_ibi().
 166  */
 167 void i3c_device_free_ibi(struct i3c_device *dev)
 168 {
 169         i3c_bus_normaluse_lock(dev->bus);
 170         if (dev->desc) {
 171                 mutex_lock(&dev->desc->ibi_lock);
 172                 i3c_dev_free_ibi_locked(dev->desc);
 173                 mutex_unlock(&dev->desc->ibi_lock);
 174         }
 175         i3c_bus_normaluse_unlock(dev->bus);
 176 }
 177 EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
 178 
 179 /**
 180  * i3cdev_to_dev() - Returns the device embedded in @i3cdev
 181  * @i3cdev: I3C device
 182  *
 183  * Return: a pointer to a device object.
 184  */
 185 struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
 186 {
 187         return &i3cdev->dev;
 188 }
 189 EXPORT_SYMBOL_GPL(i3cdev_to_dev);
 190 
 191 /**
 192  * dev_to_i3cdev() - Returns the I3C device containing @dev
 193  * @dev: device object
 194  *
 195  * Return: a pointer to an I3C device object.
 196  */
 197 struct i3c_device *dev_to_i3cdev(struct device *dev)
 198 {
 199         return container_of(dev, struct i3c_device, dev);
 200 }
 201 EXPORT_SYMBOL_GPL(dev_to_i3cdev);
 202 
 203 /**
 204  * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
 205  * @i3cdev: I3C device
 206  * @id_table: I3C device match table
 207  *
 208  * Return: a pointer to an i3c_device_id object or NULL if there's no match.
 209  */
 210 const struct i3c_device_id *
 211 i3c_device_match_id(struct i3c_device *i3cdev,
 212                     const struct i3c_device_id *id_table)
 213 {
 214         struct i3c_device_info devinfo;
 215         const struct i3c_device_id *id;
 216 
 217         i3c_device_get_info(i3cdev, &devinfo);
 218 
 219         /*
 220          * The lower 32bits of the provisional ID is just filled with a random
 221          * value, try to match using DCR info.
 222          */
 223         if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
 224                 u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
 225                 u16 part = I3C_PID_PART_ID(devinfo.pid);
 226                 u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
 227 
 228                 /* First try to match by manufacturer/part ID. */
 229                 for (id = id_table; id->match_flags != 0; id++) {
 230                         if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
 231                             I3C_MATCH_MANUF_AND_PART)
 232                                 continue;
 233 
 234                         if (manuf != id->manuf_id || part != id->part_id)
 235                                 continue;
 236 
 237                         if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
 238                             ext_info != id->extra_info)
 239                                 continue;
 240 
 241                         return id;
 242                 }
 243         }
 244 
 245         /* Fallback to DCR match. */
 246         for (id = id_table; id->match_flags != 0; id++) {
 247                 if ((id->match_flags & I3C_MATCH_DCR) &&
 248                     id->dcr == devinfo.dcr)
 249                         return id;
 250         }
 251 
 252         return NULL;
 253 }
 254 EXPORT_SYMBOL_GPL(i3c_device_match_id);
 255 
 256 /**
 257  * i3c_driver_register_with_owner() - register an I3C device driver
 258  *
 259  * @drv: driver to register
 260  * @owner: module that owns this driver
 261  *
 262  * Register @drv to the core.
 263  *
 264  * Return: 0 in case of success, a negative error core otherwise.
 265  */
 266 int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
 267 {
 268         drv->driver.owner = owner;
 269         drv->driver.bus = &i3c_bus_type;
 270 
 271         return driver_register(&drv->driver);
 272 }
 273 EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
 274 
 275 /**
 276  * i3c_driver_unregister() - unregister an I3C device driver
 277  *
 278  * @drv: driver to unregister
 279  *
 280  * Unregister @drv.
 281  */
 282 void i3c_driver_unregister(struct i3c_driver *drv)
 283 {
 284         driver_unregister(&drv->driver);
 285 }
 286 EXPORT_SYMBOL_GPL(i3c_driver_unregister);

/* [<][>][^][v][top][bottom][index][help] */