xref: /openbmc/linux/drivers/i3c/device.c (revision 3a379bbcea0af6280e1ca0d1edfcf4e68cde6ee0)
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