xref: /linux/drivers/i3c/device.c (revision 546b0ad6a87297a4268bc336aea57173008428e8)
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:
30  * * 0 in case of success, a negative error core otherwise.
31  * * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or
32  *   controller role request) win the bus. Client driver needs to resend the
33  *   'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
34  *   5.1.2.2.3.
35  */
i3c_device_do_priv_xfers(struct i3c_device * dev,struct i3c_priv_xfer * xfers,int nxfers)36 int i3c_device_do_priv_xfers(struct i3c_device *dev,
37 			     struct i3c_priv_xfer *xfers,
38 			     int nxfers)
39 {
40 	int ret, i;
41 
42 	if (nxfers < 1)
43 		return 0;
44 
45 	for (i = 0; i < nxfers; i++) {
46 		if (!xfers[i].len || !xfers[i].data.in)
47 			return -EINVAL;
48 	}
49 
50 	i3c_bus_normaluse_lock(dev->bus);
51 	ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
52 	i3c_bus_normaluse_unlock(dev->bus);
53 
54 	return ret;
55 }
56 EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
57 
58 /**
59  * i3c_device_do_setdasa() - do I3C dynamic address assignement with
60  *                           static address
61  *
62  * @dev: device with which the DAA should be done
63  *
64  * Return: 0 in case of success, a negative error core otherwise.
65  */
i3c_device_do_setdasa(struct i3c_device * dev)66 int i3c_device_do_setdasa(struct i3c_device *dev)
67 {
68 	int ret;
69 
70 	i3c_bus_normaluse_lock(dev->bus);
71 	ret = i3c_dev_setdasa_locked(dev->desc);
72 	i3c_bus_normaluse_unlock(dev->bus);
73 
74 	return ret;
75 }
76 EXPORT_SYMBOL_GPL(i3c_device_do_setdasa);
77 
78 /**
79  * i3c_device_get_info() - get I3C device information
80  *
81  * @dev: device we want information on
82  * @info: the information object to fill in
83  *
84  * Retrieve I3C dev info.
85  */
i3c_device_get_info(const struct i3c_device * dev,struct i3c_device_info * info)86 void i3c_device_get_info(const struct i3c_device *dev,
87 			 struct i3c_device_info *info)
88 {
89 	if (!info)
90 		return;
91 
92 	i3c_bus_normaluse_lock(dev->bus);
93 	if (dev->desc)
94 		*info = dev->desc->info;
95 	i3c_bus_normaluse_unlock(dev->bus);
96 }
97 EXPORT_SYMBOL_GPL(i3c_device_get_info);
98 
99 /**
100  * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
101  * @dev: device on which IBIs should be disabled
102  *
103  * This function disable IBIs coming from a specific device and wait for
104  * all pending IBIs to be processed.
105  *
106  * Return: 0 in case of success, a negative error core otherwise.
107  */
i3c_device_disable_ibi(struct i3c_device * dev)108 int i3c_device_disable_ibi(struct i3c_device *dev)
109 {
110 	int ret = -ENOENT;
111 
112 	i3c_bus_normaluse_lock(dev->bus);
113 	if (dev->desc) {
114 		mutex_lock(&dev->desc->ibi_lock);
115 		ret = i3c_dev_disable_ibi_locked(dev->desc);
116 		mutex_unlock(&dev->desc->ibi_lock);
117 	}
118 	i3c_bus_normaluse_unlock(dev->bus);
119 
120 	return ret;
121 }
122 EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
123 
124 /**
125  * i3c_device_enable_ibi() - Enable IBIs coming from a specific device
126  * @dev: device on which IBIs should be enabled
127  *
128  * This function enable IBIs coming from a specific device and wait for
129  * all pending IBIs to be processed. This should be called on a device
130  * where i3c_device_request_ibi() has succeeded.
131  *
132  * Note that IBIs from this device might be received before this function
133  * returns to its caller.
134  *
135  * Return: 0 in case of success, a negative error core otherwise.
136  */
i3c_device_enable_ibi(struct i3c_device * dev)137 int i3c_device_enable_ibi(struct i3c_device *dev)
138 {
139 	int ret = -ENOENT;
140 
141 	i3c_bus_normaluse_lock(dev->bus);
142 	if (dev->desc) {
143 		mutex_lock(&dev->desc->ibi_lock);
144 		ret = i3c_dev_enable_ibi_locked(dev->desc);
145 		mutex_unlock(&dev->desc->ibi_lock);
146 	}
147 	i3c_bus_normaluse_unlock(dev->bus);
148 
149 	return ret;
150 }
151 EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
152 
153 /**
154  * i3c_device_request_ibi() - Request an IBI
155  * @dev: device for which we should enable IBIs
156  * @req: setup requested for this IBI
157  *
158  * This function is responsible for pre-allocating all resources needed to
159  * process IBIs coming from @dev. When this function returns, the IBI is not
160  * enabled until i3c_device_enable_ibi() is called.
161  *
162  * Return: 0 in case of success, a negative error core otherwise.
163  */
i3c_device_request_ibi(struct i3c_device * dev,const struct i3c_ibi_setup * req)164 int i3c_device_request_ibi(struct i3c_device *dev,
165 			   const struct i3c_ibi_setup *req)
166 {
167 	int ret = -ENOENT;
168 
169 	if (!req->handler || !req->num_slots)
170 		return -EINVAL;
171 
172 	i3c_bus_normaluse_lock(dev->bus);
173 	if (dev->desc) {
174 		mutex_lock(&dev->desc->ibi_lock);
175 		ret = i3c_dev_request_ibi_locked(dev->desc, req);
176 		mutex_unlock(&dev->desc->ibi_lock);
177 	}
178 	i3c_bus_normaluse_unlock(dev->bus);
179 
180 	return ret;
181 }
182 EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
183 
184 /**
185  * i3c_device_free_ibi() - Free all resources needed for IBI handling
186  * @dev: device on which you want to release IBI resources
187  *
188  * This function is responsible for de-allocating resources previously
189  * allocated by i3c_device_request_ibi(). It should be called after disabling
190  * IBIs with i3c_device_disable_ibi().
191  */
i3c_device_free_ibi(struct i3c_device * dev)192 void i3c_device_free_ibi(struct i3c_device *dev)
193 {
194 	i3c_bus_normaluse_lock(dev->bus);
195 	if (dev->desc) {
196 		mutex_lock(&dev->desc->ibi_lock);
197 		i3c_dev_free_ibi_locked(dev->desc);
198 		mutex_unlock(&dev->desc->ibi_lock);
199 	}
200 	i3c_bus_normaluse_unlock(dev->bus);
201 }
202 EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
203 
204 /**
205  * i3cdev_to_dev() - Returns the device embedded in @i3cdev
206  * @i3cdev: I3C device
207  *
208  * Return: a pointer to a device object.
209  */
i3cdev_to_dev(struct i3c_device * i3cdev)210 struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
211 {
212 	return &i3cdev->dev;
213 }
214 EXPORT_SYMBOL_GPL(i3cdev_to_dev);
215 
216 /**
217  * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
218  * @i3cdev: I3C device
219  * @id_table: I3C device match table
220  *
221  * Return: a pointer to an i3c_device_id object or NULL if there's no match.
222  */
223 const struct i3c_device_id *
i3c_device_match_id(struct i3c_device * i3cdev,const struct i3c_device_id * id_table)224 i3c_device_match_id(struct i3c_device *i3cdev,
225 		    const struct i3c_device_id *id_table)
226 {
227 	struct i3c_device_info devinfo;
228 	const struct i3c_device_id *id;
229 	u16 manuf, part, ext_info;
230 	bool rndpid;
231 
232 	i3c_device_get_info(i3cdev, &devinfo);
233 
234 	manuf = I3C_PID_MANUF_ID(devinfo.pid);
235 	part = I3C_PID_PART_ID(devinfo.pid);
236 	ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
237 	rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
238 
239 	for (id = id_table; id->match_flags != 0; id++) {
240 		if ((id->match_flags & I3C_MATCH_DCR) &&
241 		    id->dcr != devinfo.dcr)
242 			continue;
243 
244 		if ((id->match_flags & I3C_MATCH_MANUF) &&
245 		    id->manuf_id != manuf)
246 			continue;
247 
248 		if ((id->match_flags & I3C_MATCH_PART) &&
249 		    (rndpid || id->part_id != part))
250 			continue;
251 
252 		if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
253 		    (rndpid || id->extra_info != ext_info))
254 			continue;
255 
256 		return id;
257 	}
258 
259 	return NULL;
260 }
261 EXPORT_SYMBOL_GPL(i3c_device_match_id);
262 
263 /**
264  * i3c_driver_register_with_owner() - register an I3C device driver
265  *
266  * @drv: driver to register
267  * @owner: module that owns this driver
268  *
269  * Register @drv to the core.
270  *
271  * Return: 0 in case of success, a negative error core otherwise.
272  */
i3c_driver_register_with_owner(struct i3c_driver * drv,struct module * owner)273 int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
274 {
275 	drv->driver.owner = owner;
276 	drv->driver.bus = &i3c_bus_type;
277 
278 	if (!drv->probe) {
279 		pr_err("Trying to register an i3c driver without probe callback\n");
280 		return -EINVAL;
281 	}
282 
283 	return driver_register(&drv->driver);
284 }
285 EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
286 
287 /**
288  * i3c_driver_unregister() - unregister an I3C device driver
289  *
290  * @drv: driver to unregister
291  *
292  * Unregister @drv.
293  */
i3c_driver_unregister(struct i3c_driver * drv)294 void i3c_driver_unregister(struct i3c_driver *drv)
295 {
296 	driver_unregister(&drv->driver);
297 }
298 EXPORT_SYMBOL_GPL(i3c_driver_unregister);
299