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_driver_register_with_owner() - register an I3C device driver
 205 *
 206 * @drv: driver to register
 207 * @owner: module that owns this driver
 208 *
 209 * Register @drv to the core.
 210 *
 211 * Return: 0 in case of success, a negative error core otherwise.
 212 */
 213int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
 214{
 215        drv->driver.owner = owner;
 216        drv->driver.bus = &i3c_bus_type;
 217
 218        return driver_register(&drv->driver);
 219}
 220EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
 221
 222/**
 223 * i3c_driver_unregister() - unregister an I3C device driver
 224 *
 225 * @drv: driver to unregister
 226 *
 227 * Unregister @drv.
 228 */
 229void i3c_driver_unregister(struct i3c_driver *drv)
 230{
 231        driver_unregister(&drv->driver);
 232}
 233EXPORT_SYMBOL_GPL(i3c_driver_unregister);
 234