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_xfers() - do I3C transfers directed to a specific device
19 *
20 * @dev: device with which the transfers should be done
21 * @xfers: array of transfers
22 * @nxfers: number of transfers
23 * @mode: transfer mode
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_xfers(struct i3c_device * dev,struct i3c_xfer * xfers,int nxfers,enum i3c_xfer_mode mode)36 int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
37 int nxfers, enum i3c_xfer_mode mode)
38 {
39 int ret, i;
40
41 if (nxfers < 1)
42 return 0;
43
44 for (i = 0; i < nxfers; i++) {
45 if (!xfers[i].len || !xfers[i].data.in)
46 return -EINVAL;
47 }
48
49 ret = i3c_bus_rpm_get(dev->bus);
50 if (ret)
51 return ret;
52
53 i3c_bus_normaluse_lock(dev->bus);
54 ret = i3c_dev_do_xfers_locked(dev->desc, xfers, nxfers, mode);
55 i3c_bus_normaluse_unlock(dev->bus);
56
57 i3c_bus_rpm_put(dev->bus);
58
59 return ret;
60 }
61 EXPORT_SYMBOL_GPL(i3c_device_do_xfers);
62
63 /**
64 * i3c_device_do_setdasa() - do I3C dynamic address assignement with
65 * static address
66 *
67 * @dev: device with which the DAA should be done
68 *
69 * Return: 0 in case of success, a negative error core otherwise.
70 */
i3c_device_do_setdasa(struct i3c_device * dev)71 int i3c_device_do_setdasa(struct i3c_device *dev)
72 {
73 int ret;
74
75 ret = i3c_bus_rpm_get(dev->bus);
76 if (ret)
77 return ret;
78
79 i3c_bus_normaluse_lock(dev->bus);
80 ret = i3c_dev_setdasa_locked(dev->desc);
81 i3c_bus_normaluse_unlock(dev->bus);
82
83 i3c_bus_rpm_put(dev->bus);
84
85 return ret;
86 }
87 EXPORT_SYMBOL_GPL(i3c_device_do_setdasa);
88
89 /**
90 * i3c_device_get_info() - get I3C device information
91 *
92 * @dev: device we want information on
93 * @info: the information object to fill in
94 *
95 * Retrieve I3C dev info.
96 */
i3c_device_get_info(const struct i3c_device * dev,struct i3c_device_info * info)97 void i3c_device_get_info(const struct i3c_device *dev,
98 struct i3c_device_info *info)
99 {
100 if (!info)
101 return;
102
103 i3c_bus_normaluse_lock(dev->bus);
104 if (dev->desc)
105 *info = dev->desc->info;
106 i3c_bus_normaluse_unlock(dev->bus);
107 }
108 EXPORT_SYMBOL_GPL(i3c_device_get_info);
109
110 /**
111 * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
112 * @dev: device on which IBIs should be disabled
113 *
114 * This function disable IBIs coming from a specific device and wait for
115 * all pending IBIs to be processed.
116 *
117 * Return: 0 in case of success, a negative error core otherwise.
118 */
i3c_device_disable_ibi(struct i3c_device * dev)119 int i3c_device_disable_ibi(struct i3c_device *dev)
120 {
121 int ret;
122
123 if (i3c_bus_rpm_ibi_allowed(dev->bus)) {
124 ret = i3c_bus_rpm_get(dev->bus);
125 if (ret)
126 return ret;
127 }
128
129 i3c_bus_normaluse_lock(dev->bus);
130 if (dev->desc) {
131 mutex_lock(&dev->desc->ibi_lock);
132 ret = i3c_dev_disable_ibi_locked(dev->desc);
133 mutex_unlock(&dev->desc->ibi_lock);
134 } else {
135 ret = -ENOENT;
136 }
137 i3c_bus_normaluse_unlock(dev->bus);
138
139 if (!ret || i3c_bus_rpm_ibi_allowed(dev->bus))
140 i3c_bus_rpm_put(dev->bus);
141
142 return ret;
143 }
144 EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
145
146 /**
147 * i3c_device_enable_ibi() - Enable IBIs coming from a specific device
148 * @dev: device on which IBIs should be enabled
149 *
150 * This function enable IBIs coming from a specific device and wait for
151 * all pending IBIs to be processed. This should be called on a device
152 * where i3c_device_request_ibi() has succeeded.
153 *
154 * Note that IBIs from this device might be received before this function
155 * returns to its caller.
156 *
157 * Return: 0 in case of success, a negative error core otherwise.
158 */
i3c_device_enable_ibi(struct i3c_device * dev)159 int i3c_device_enable_ibi(struct i3c_device *dev)
160 {
161 int ret;
162
163 ret = i3c_bus_rpm_get(dev->bus);
164 if (ret)
165 return ret;
166
167 i3c_bus_normaluse_lock(dev->bus);
168 if (dev->desc) {
169 mutex_lock(&dev->desc->ibi_lock);
170 ret = i3c_dev_enable_ibi_locked(dev->desc);
171 mutex_unlock(&dev->desc->ibi_lock);
172 } else {
173 ret = -ENOENT;
174 }
175 i3c_bus_normaluse_unlock(dev->bus);
176
177 if (ret || i3c_bus_rpm_ibi_allowed(dev->bus))
178 i3c_bus_rpm_put(dev->bus);
179
180 return ret;
181 }
182 EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
183
184 /**
185 * i3c_device_request_ibi() - Request an IBI
186 * @dev: device for which we should enable IBIs
187 * @req: setup requested for this IBI
188 *
189 * This function is responsible for pre-allocating all resources needed to
190 * process IBIs coming from @dev. When this function returns, the IBI is not
191 * enabled until i3c_device_enable_ibi() is called.
192 *
193 * Return: 0 in case of success, a negative error core otherwise.
194 */
i3c_device_request_ibi(struct i3c_device * dev,const struct i3c_ibi_setup * req)195 int i3c_device_request_ibi(struct i3c_device *dev,
196 const struct i3c_ibi_setup *req)
197 {
198 int ret;
199
200 if (!req->handler || !req->num_slots)
201 return -EINVAL;
202
203 ret = i3c_bus_rpm_get(dev->bus);
204 if (ret)
205 return ret;
206
207 i3c_bus_normaluse_lock(dev->bus);
208 if (dev->desc) {
209 mutex_lock(&dev->desc->ibi_lock);
210 ret = i3c_dev_request_ibi_locked(dev->desc, req);
211 mutex_unlock(&dev->desc->ibi_lock);
212 } else {
213 ret = -ENOENT;
214 }
215 i3c_bus_normaluse_unlock(dev->bus);
216
217 i3c_bus_rpm_put(dev->bus);
218
219 return ret;
220 }
221 EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
222
223 /**
224 * i3c_device_free_ibi() - Free all resources needed for IBI handling
225 * @dev: device on which you want to release IBI resources
226 *
227 * This function is responsible for de-allocating resources previously
228 * allocated by i3c_device_request_ibi(). It should be called after disabling
229 * IBIs with i3c_device_disable_ibi().
230 */
i3c_device_free_ibi(struct i3c_device * dev)231 void i3c_device_free_ibi(struct i3c_device *dev)
232 {
233 i3c_bus_normaluse_lock(dev->bus);
234 if (dev->desc) {
235 mutex_lock(&dev->desc->ibi_lock);
236 i3c_dev_free_ibi_locked(dev->desc);
237 mutex_unlock(&dev->desc->ibi_lock);
238 }
239 i3c_bus_normaluse_unlock(dev->bus);
240 }
241 EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
242
243 /**
244 * i3cdev_to_dev() - Returns the device embedded in @i3cdev
245 * @i3cdev: I3C device
246 *
247 * Return: a pointer to a device object.
248 */
i3cdev_to_dev(struct i3c_device * i3cdev)249 struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
250 {
251 return &i3cdev->dev;
252 }
253 EXPORT_SYMBOL_GPL(i3cdev_to_dev);
254
255 /**
256 * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
257 * @i3cdev: I3C device
258 * @id_table: I3C device match table
259 *
260 * Return: a pointer to an i3c_device_id object or NULL if there's no match.
261 */
262 const struct i3c_device_id *
i3c_device_match_id(struct i3c_device * i3cdev,const struct i3c_device_id * id_table)263 i3c_device_match_id(struct i3c_device *i3cdev,
264 const struct i3c_device_id *id_table)
265 {
266 struct i3c_device_info devinfo;
267 const struct i3c_device_id *id;
268 u16 manuf, part, ext_info;
269 bool rndpid;
270
271 i3c_device_get_info(i3cdev, &devinfo);
272
273 manuf = I3C_PID_MANUF_ID(devinfo.pid);
274 part = I3C_PID_PART_ID(devinfo.pid);
275 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
276 rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
277
278 for (id = id_table; id->match_flags != 0; id++) {
279 if ((id->match_flags & I3C_MATCH_DCR) &&
280 id->dcr != devinfo.dcr)
281 continue;
282
283 if ((id->match_flags & I3C_MATCH_MANUF) &&
284 id->manuf_id != manuf)
285 continue;
286
287 if ((id->match_flags & I3C_MATCH_PART) &&
288 (rndpid || id->part_id != part))
289 continue;
290
291 if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
292 (rndpid || id->extra_info != ext_info))
293 continue;
294
295 return id;
296 }
297
298 return NULL;
299 }
300 EXPORT_SYMBOL_GPL(i3c_device_match_id);
301
302 /**
303 * i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
304 * connected master controller.
305 * @dev: I3C device
306 *
307 * Return: a bit mask, which supported transfer mode, bit position is defined at
308 * enum i3c_hdr_mode
309 */
i3c_device_get_supported_xfer_mode(struct i3c_device * dev)310 u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
311 {
312 return i3c_dev_get_master(dev->desc)->this->info.hdr_cap | BIT(I3C_SDR);
313 }
314 EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
315
316 /**
317 * i3c_driver_register_with_owner() - register an I3C device driver
318 *
319 * @drv: driver to register
320 * @owner: module that owns this driver
321 *
322 * Register @drv to the core.
323 *
324 * Return: 0 in case of success, a negative error core otherwise.
325 */
i3c_driver_register_with_owner(struct i3c_driver * drv,struct module * owner)326 int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
327 {
328 drv->driver.owner = owner;
329 drv->driver.bus = &i3c_bus_type;
330
331 if (!drv->probe) {
332 pr_err("Trying to register an i3c driver without probe callback\n");
333 return -EINVAL;
334 }
335
336 return driver_register(&drv->driver);
337 }
338 EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
339
340 /**
341 * i3c_driver_unregister() - unregister an I3C device driver
342 *
343 * @drv: driver to unregister
344 *
345 * Unregister @drv.
346 */
i3c_driver_unregister(struct i3c_driver * drv)347 void i3c_driver_unregister(struct i3c_driver *drv)
348 {
349 driver_unregister(&drv->driver);
350 }
351 EXPORT_SYMBOL_GPL(i3c_driver_unregister);
352