1*3a379bbcSBoris Brezillon // SPDX-License-Identifier: GPL-2.0 2*3a379bbcSBoris Brezillon /* 3*3a379bbcSBoris Brezillon * Copyright (C) 2018 Cadence Design Systems Inc. 4*3a379bbcSBoris Brezillon * 5*3a379bbcSBoris Brezillon * Author: Boris Brezillon <boris.brezillon@bootlin.com> 6*3a379bbcSBoris Brezillon */ 7*3a379bbcSBoris Brezillon 8*3a379bbcSBoris Brezillon #include <linux/atomic.h> 9*3a379bbcSBoris Brezillon #include <linux/bug.h> 10*3a379bbcSBoris Brezillon #include <linux/completion.h> 11*3a379bbcSBoris Brezillon #include <linux/device.h> 12*3a379bbcSBoris Brezillon #include <linux/mutex.h> 13*3a379bbcSBoris Brezillon #include <linux/slab.h> 14*3a379bbcSBoris Brezillon 15*3a379bbcSBoris Brezillon #include "internals.h" 16*3a379bbcSBoris Brezillon 17*3a379bbcSBoris Brezillon /** 18*3a379bbcSBoris Brezillon * i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a 19*3a379bbcSBoris Brezillon * specific device 20*3a379bbcSBoris Brezillon * 21*3a379bbcSBoris Brezillon * @dev: device with which the transfers should be done 22*3a379bbcSBoris Brezillon * @xfers: array of transfers 23*3a379bbcSBoris Brezillon * @nxfers: number of transfers 24*3a379bbcSBoris Brezillon * 25*3a379bbcSBoris Brezillon * Initiate one or several private SDR transfers with @dev. 26*3a379bbcSBoris Brezillon * 27*3a379bbcSBoris Brezillon * This function can sleep and thus cannot be called in atomic context. 28*3a379bbcSBoris Brezillon * 29*3a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 30*3a379bbcSBoris Brezillon */ 31*3a379bbcSBoris Brezillon int i3c_device_do_priv_xfers(struct i3c_device *dev, 32*3a379bbcSBoris Brezillon struct i3c_priv_xfer *xfers, 33*3a379bbcSBoris Brezillon int nxfers) 34*3a379bbcSBoris Brezillon { 35*3a379bbcSBoris Brezillon int ret, i; 36*3a379bbcSBoris Brezillon 37*3a379bbcSBoris Brezillon if (nxfers < 1) 38*3a379bbcSBoris Brezillon return 0; 39*3a379bbcSBoris Brezillon 40*3a379bbcSBoris Brezillon for (i = 0; i < nxfers; i++) { 41*3a379bbcSBoris Brezillon if (!xfers[i].len || !xfers[i].data.in) 42*3a379bbcSBoris Brezillon return -EINVAL; 43*3a379bbcSBoris Brezillon } 44*3a379bbcSBoris Brezillon 45*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 46*3a379bbcSBoris Brezillon ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers); 47*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 48*3a379bbcSBoris Brezillon 49*3a379bbcSBoris Brezillon return ret; 50*3a379bbcSBoris Brezillon } 51*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers); 52*3a379bbcSBoris Brezillon 53*3a379bbcSBoris Brezillon /** 54*3a379bbcSBoris Brezillon * i3c_device_get_info() - get I3C device information 55*3a379bbcSBoris Brezillon * 56*3a379bbcSBoris Brezillon * @dev: device we want information on 57*3a379bbcSBoris Brezillon * @info: the information object to fill in 58*3a379bbcSBoris Brezillon * 59*3a379bbcSBoris Brezillon * Retrieve I3C dev info. 60*3a379bbcSBoris Brezillon */ 61*3a379bbcSBoris Brezillon void i3c_device_get_info(struct i3c_device *dev, 62*3a379bbcSBoris Brezillon struct i3c_device_info *info) 63*3a379bbcSBoris Brezillon { 64*3a379bbcSBoris Brezillon if (!info) 65*3a379bbcSBoris Brezillon return; 66*3a379bbcSBoris Brezillon 67*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 68*3a379bbcSBoris Brezillon if (dev->desc) 69*3a379bbcSBoris Brezillon *info = dev->desc->info; 70*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 71*3a379bbcSBoris Brezillon } 72*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_get_info); 73*3a379bbcSBoris Brezillon 74*3a379bbcSBoris Brezillon /** 75*3a379bbcSBoris Brezillon * i3c_device_disable_ibi() - Disable IBIs coming from a specific device 76*3a379bbcSBoris Brezillon * @dev: device on which IBIs should be disabled 77*3a379bbcSBoris Brezillon * 78*3a379bbcSBoris Brezillon * This function disable IBIs coming from a specific device and wait for 79*3a379bbcSBoris Brezillon * all pending IBIs to be processed. 80*3a379bbcSBoris Brezillon * 81*3a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 82*3a379bbcSBoris Brezillon */ 83*3a379bbcSBoris Brezillon int i3c_device_disable_ibi(struct i3c_device *dev) 84*3a379bbcSBoris Brezillon { 85*3a379bbcSBoris Brezillon int ret = -ENOENT; 86*3a379bbcSBoris Brezillon 87*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 88*3a379bbcSBoris Brezillon if (dev->desc) { 89*3a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 90*3a379bbcSBoris Brezillon ret = i3c_dev_disable_ibi_locked(dev->desc); 91*3a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 92*3a379bbcSBoris Brezillon } 93*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 94*3a379bbcSBoris Brezillon 95*3a379bbcSBoris Brezillon return ret; 96*3a379bbcSBoris Brezillon } 97*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_disable_ibi); 98*3a379bbcSBoris Brezillon 99*3a379bbcSBoris Brezillon /** 100*3a379bbcSBoris Brezillon * i3c_device_enable_ibi() - Enable IBIs coming from a specific device 101*3a379bbcSBoris Brezillon * @dev: device on which IBIs should be enabled 102*3a379bbcSBoris Brezillon * 103*3a379bbcSBoris Brezillon * This function enable IBIs coming from a specific device and wait for 104*3a379bbcSBoris Brezillon * all pending IBIs to be processed. This should be called on a device 105*3a379bbcSBoris Brezillon * where i3c_device_request_ibi() has succeeded. 106*3a379bbcSBoris Brezillon * 107*3a379bbcSBoris Brezillon * Note that IBIs from this device might be received before this function 108*3a379bbcSBoris Brezillon * returns to its caller. 109*3a379bbcSBoris Brezillon * 110*3a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 111*3a379bbcSBoris Brezillon */ 112*3a379bbcSBoris Brezillon int i3c_device_enable_ibi(struct i3c_device *dev) 113*3a379bbcSBoris Brezillon { 114*3a379bbcSBoris Brezillon int ret = -ENOENT; 115*3a379bbcSBoris Brezillon 116*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 117*3a379bbcSBoris Brezillon if (dev->desc) { 118*3a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 119*3a379bbcSBoris Brezillon ret = i3c_dev_enable_ibi_locked(dev->desc); 120*3a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 121*3a379bbcSBoris Brezillon } 122*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 123*3a379bbcSBoris Brezillon 124*3a379bbcSBoris Brezillon return ret; 125*3a379bbcSBoris Brezillon } 126*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_enable_ibi); 127*3a379bbcSBoris Brezillon 128*3a379bbcSBoris Brezillon /** 129*3a379bbcSBoris Brezillon * i3c_device_request_ibi() - Request an IBI 130*3a379bbcSBoris Brezillon * @dev: device for which we should enable IBIs 131*3a379bbcSBoris Brezillon * @req: setup requested for this IBI 132*3a379bbcSBoris Brezillon * 133*3a379bbcSBoris Brezillon * This function is responsible for pre-allocating all resources needed to 134*3a379bbcSBoris Brezillon * process IBIs coming from @dev. When this function returns, the IBI is not 135*3a379bbcSBoris Brezillon * enabled until i3c_device_enable_ibi() is called. 136*3a379bbcSBoris Brezillon * 137*3a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 138*3a379bbcSBoris Brezillon */ 139*3a379bbcSBoris Brezillon int i3c_device_request_ibi(struct i3c_device *dev, 140*3a379bbcSBoris Brezillon const struct i3c_ibi_setup *req) 141*3a379bbcSBoris Brezillon { 142*3a379bbcSBoris Brezillon int ret = -ENOENT; 143*3a379bbcSBoris Brezillon 144*3a379bbcSBoris Brezillon if (!req->handler || !req->num_slots) 145*3a379bbcSBoris Brezillon return -EINVAL; 146*3a379bbcSBoris Brezillon 147*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 148*3a379bbcSBoris Brezillon if (dev->desc) { 149*3a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 150*3a379bbcSBoris Brezillon ret = i3c_dev_request_ibi_locked(dev->desc, req); 151*3a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 152*3a379bbcSBoris Brezillon } 153*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 154*3a379bbcSBoris Brezillon 155*3a379bbcSBoris Brezillon return ret; 156*3a379bbcSBoris Brezillon } 157*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_request_ibi); 158*3a379bbcSBoris Brezillon 159*3a379bbcSBoris Brezillon /** 160*3a379bbcSBoris Brezillon * i3c_device_free_ibi() - Free all resources needed for IBI handling 161*3a379bbcSBoris Brezillon * @dev: device on which you want to release IBI resources 162*3a379bbcSBoris Brezillon * 163*3a379bbcSBoris Brezillon * This function is responsible for de-allocating resources previously 164*3a379bbcSBoris Brezillon * allocated by i3c_device_request_ibi(). It should be called after disabling 165*3a379bbcSBoris Brezillon * IBIs with i3c_device_disable_ibi(). 166*3a379bbcSBoris Brezillon */ 167*3a379bbcSBoris Brezillon void i3c_device_free_ibi(struct i3c_device *dev) 168*3a379bbcSBoris Brezillon { 169*3a379bbcSBoris Brezillon i3c_bus_normaluse_lock(dev->bus); 170*3a379bbcSBoris Brezillon if (dev->desc) { 171*3a379bbcSBoris Brezillon mutex_lock(&dev->desc->ibi_lock); 172*3a379bbcSBoris Brezillon i3c_dev_free_ibi_locked(dev->desc); 173*3a379bbcSBoris Brezillon mutex_unlock(&dev->desc->ibi_lock); 174*3a379bbcSBoris Brezillon } 175*3a379bbcSBoris Brezillon i3c_bus_normaluse_unlock(dev->bus); 176*3a379bbcSBoris Brezillon } 177*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_device_free_ibi); 178*3a379bbcSBoris Brezillon 179*3a379bbcSBoris Brezillon /** 180*3a379bbcSBoris Brezillon * i3cdev_to_dev() - Returns the device embedded in @i3cdev 181*3a379bbcSBoris Brezillon * @i3cdev: I3C device 182*3a379bbcSBoris Brezillon * 183*3a379bbcSBoris Brezillon * Return: a pointer to a device object. 184*3a379bbcSBoris Brezillon */ 185*3a379bbcSBoris Brezillon struct device *i3cdev_to_dev(struct i3c_device *i3cdev) 186*3a379bbcSBoris Brezillon { 187*3a379bbcSBoris Brezillon return &i3cdev->dev; 188*3a379bbcSBoris Brezillon } 189*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3cdev_to_dev); 190*3a379bbcSBoris Brezillon 191*3a379bbcSBoris Brezillon /** 192*3a379bbcSBoris Brezillon * dev_to_i3cdev() - Returns the I3C device containing @dev 193*3a379bbcSBoris Brezillon * @dev: device object 194*3a379bbcSBoris Brezillon * 195*3a379bbcSBoris Brezillon * Return: a pointer to an I3C device object. 196*3a379bbcSBoris Brezillon */ 197*3a379bbcSBoris Brezillon struct i3c_device *dev_to_i3cdev(struct device *dev) 198*3a379bbcSBoris Brezillon { 199*3a379bbcSBoris Brezillon return container_of(dev, struct i3c_device, dev); 200*3a379bbcSBoris Brezillon } 201*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(dev_to_i3cdev); 202*3a379bbcSBoris Brezillon 203*3a379bbcSBoris Brezillon /** 204*3a379bbcSBoris Brezillon * i3c_driver_register_with_owner() - register an I3C device driver 205*3a379bbcSBoris Brezillon * 206*3a379bbcSBoris Brezillon * @drv: driver to register 207*3a379bbcSBoris Brezillon * @owner: module that owns this driver 208*3a379bbcSBoris Brezillon * 209*3a379bbcSBoris Brezillon * Register @drv to the core. 210*3a379bbcSBoris Brezillon * 211*3a379bbcSBoris Brezillon * Return: 0 in case of success, a negative error core otherwise. 212*3a379bbcSBoris Brezillon */ 213*3a379bbcSBoris Brezillon int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner) 214*3a379bbcSBoris Brezillon { 215*3a379bbcSBoris Brezillon drv->driver.owner = owner; 216*3a379bbcSBoris Brezillon drv->driver.bus = &i3c_bus_type; 217*3a379bbcSBoris Brezillon 218*3a379bbcSBoris Brezillon return driver_register(&drv->driver); 219*3a379bbcSBoris Brezillon } 220*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner); 221*3a379bbcSBoris Brezillon 222*3a379bbcSBoris Brezillon /** 223*3a379bbcSBoris Brezillon * i3c_driver_unregister() - unregister an I3C device driver 224*3a379bbcSBoris Brezillon * 225*3a379bbcSBoris Brezillon * @drv: driver to unregister 226*3a379bbcSBoris Brezillon * 227*3a379bbcSBoris Brezillon * Unregister @drv. 228*3a379bbcSBoris Brezillon */ 229*3a379bbcSBoris Brezillon void i3c_driver_unregister(struct i3c_driver *drv) 230*3a379bbcSBoris Brezillon { 231*3a379bbcSBoris Brezillon driver_unregister(&drv->driver); 232*3a379bbcSBoris Brezillon } 233*3a379bbcSBoris Brezillon EXPORT_SYMBOL_GPL(i3c_driver_unregister); 234