linux/drivers/i3c/device.c
<<
>>
Prefs
   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 */
  31int 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}
  51EXPORT_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 */
  61void 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}
  72EXPORT_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 */
  83int 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}
  97EXPORT_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 */
 112int 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}
 126EXPORT_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 */
 139int 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}
 157EXPORT_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 */
 167void 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}
 177EXPORT_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 */
 185struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
 186{
 187        return &i3cdev->dev;
 188}
 189EXPORT_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 */
 197struct i3c_device *dev_to_i3cdev(struct device *dev)
 198{
 199        return container_of(dev, struct i3c_device, dev);
 200}
 201EXPORT_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 */
 210const struct i3c_device_id *
 211i3c_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        u16 manuf, part, ext_info;
 217        bool rndpid;
 218
 219        i3c_device_get_info(i3cdev, &devinfo);
 220
 221        manuf = I3C_PID_MANUF_ID(devinfo.pid);
 222        part = I3C_PID_PART_ID(devinfo.pid);
 223        ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
 224        rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
 225
 226        for (id = id_table; id->match_flags != 0; id++) {
 227                if ((id->match_flags & I3C_MATCH_DCR) &&
 228                    id->dcr != devinfo.dcr)
 229                        continue;
 230
 231                if ((id->match_flags & I3C_MATCH_MANUF) &&
 232                    id->manuf_id != manuf)
 233                        continue;
 234
 235                if ((id->match_flags & I3C_MATCH_PART) &&
 236                    (rndpid || id->part_id != part))
 237                        continue;
 238
 239                if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
 240                    (rndpid || id->extra_info != ext_info))
 241                        continue;
 242
 243                return id;
 244        }
 245
 246        return NULL;
 247}
 248EXPORT_SYMBOL_GPL(i3c_device_match_id);
 249
 250/**
 251 * i3c_driver_register_with_owner() - register an I3C device driver
 252 *
 253 * @drv: driver to register
 254 * @owner: module that owns this driver
 255 *
 256 * Register @drv to the core.
 257 *
 258 * Return: 0 in case of success, a negative error core otherwise.
 259 */
 260int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
 261{
 262        drv->driver.owner = owner;
 263        drv->driver.bus = &i3c_bus_type;
 264
 265        if (!drv->probe) {
 266                pr_err("Trying to register an i3c driver without probe callback\n");
 267                return -EINVAL;
 268        }
 269
 270        return driver_register(&drv->driver);
 271}
 272EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
 273
 274/**
 275 * i3c_driver_unregister() - unregister an I3C device driver
 276 *
 277 * @drv: driver to unregister
 278 *
 279 * Unregister @drv.
 280 */
 281void i3c_driver_unregister(struct i3c_driver *drv)
 282{
 283        driver_unregister(&drv->driver);
 284}
 285EXPORT_SYMBOL_GPL(i3c_driver_unregister);
 286