projects/linux·blob master · refs

352 lines · 8.6 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 Cadence Design Systems Inc.
4 *
5 * Author: Boris Brezillon <[email protected]>
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 */
36int 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}
61EXPORT_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 */
71int 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}
87EXPORT_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 */
97void 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 *info = dev->desc->info;
105 i3c_bus_normaluse_unlock(dev->bus);
106}
107EXPORT_SYMBOL_GPL(i3c_device_get_info);
108
109/**
110 * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
111 * @dev: device on which IBIs should be disabled
112 *
113 * This function disable IBIs coming from a specific device and wait for
114 * all pending IBIs to be processed.
115 *
116 * Return: 0 in case of success, a negative error core otherwise.
117 */
118int i3c_device_disable_ibi(struct i3c_device *dev)
119{
120 int ret;
121
122 if (i3c_bus_rpm_ibi_allowed(dev->bus)) {
123 ret = i3c_bus_rpm_get(dev->bus);
124 if (ret)
125 return ret;
126 }
127
128 i3c_bus_normaluse_lock(dev->bus);
129 if (dev->desc) {
130 mutex_lock(&dev->desc->ibi_lock);
131 ret = i3c_dev_disable_ibi_locked(dev->desc);
132 mutex_unlock(&dev->desc->ibi_lock);
133 } else {
134 ret = -ENOENT;
135 }
136 i3c_bus_normaluse_unlock(dev->bus);
137
138 if (!ret || i3c_bus_rpm_ibi_allowed(dev->bus))
139 i3c_bus_rpm_put(dev->bus);
140
141 return ret;
142}
143EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
144
145/**
146 * i3c_device_enable_ibi() - Enable IBIs coming from a specific device
147 * @dev: device on which IBIs should be enabled
148 *
149 * This function enable IBIs coming from a specific device and wait for
150 * all pending IBIs to be processed. This should be called on a device
151 * where i3c_device_request_ibi() has succeeded.
152 *
153 * Note that IBIs from this device might be received before this function
154 * returns to its caller.
155 *
156 * Return: 0 in case of success, a negative error core otherwise.
157 */
158int i3c_device_enable_ibi(struct i3c_device *dev)
159{
160 int ret;
161
162 ret = i3c_bus_rpm_get(dev->bus);
163 if (ret)
164 return ret;
165
166 i3c_bus_normaluse_lock(dev->bus);
167 if (dev->desc) {
168 mutex_lock(&dev->desc->ibi_lock);
169 ret = i3c_dev_enable_ibi_locked(dev->desc);
170 mutex_unlock(&dev->desc->ibi_lock);
171 } else {
172 ret = -ENOENT;
173 }
174 i3c_bus_normaluse_unlock(dev->bus);
175
176 if (ret || i3c_bus_rpm_ibi_allowed(dev->bus))
177 i3c_bus_rpm_put(dev->bus);
178
179 return ret;
180}
181EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
182
183/**
184 * i3c_device_request_ibi() - Request an IBI
185 * @dev: device for which we should enable IBIs
186 * @req: setup requested for this IBI
187 *
188 * This function is responsible for pre-allocating all resources needed to
189 * process IBIs coming from @dev. When this function returns, the IBI is not
190 * enabled until i3c_device_enable_ibi() is called.
191 *
192 * Return: 0 in case of success, a negative error core otherwise.
193 */
194int i3c_device_request_ibi(struct i3c_device *dev,
195 const struct i3c_ibi_setup *req)
196{
197 int ret;
198
199 if (!req->handler || !req->num_slots)
200 return -EINVAL;
201
202 ret = i3c_bus_rpm_get(dev->bus);
203 if (ret)
204 return ret;
205
206 i3c_bus_normaluse_lock(dev->bus);
207 if (!dev->desc) {
208 ret = -ENOENT;
209 } else if (!(dev->desc->info.bcr & I3C_BCR_IBI_REQ_CAP)) {
210 ret = -EOPNOTSUPP;
211 } else {
212 mutex_lock(&dev->desc->ibi_lock);
213 ret = i3c_dev_request_ibi_locked(dev->desc, req);
214 mutex_unlock(&dev->desc->ibi_lock);
215 }
216 i3c_bus_normaluse_unlock(dev->bus);
217
218 i3c_bus_rpm_put(dev->bus);
219
220 return ret;
221}
222EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
223
224/**
225 * i3c_device_free_ibi() - Free all resources needed for IBI handling
226 * @dev: device on which you want to release IBI resources
227 *
228 * This function is responsible for de-allocating resources previously
229 * allocated by i3c_device_request_ibi(). It should be called after disabling
230 * IBIs with i3c_device_disable_ibi().
231 */
232void i3c_device_free_ibi(struct i3c_device *dev)
233{
234 i3c_bus_normaluse_lock(dev->bus);
235 if (dev->desc) {
236 mutex_lock(&dev->desc->ibi_lock);
237 i3c_dev_free_ibi_locked(dev->desc);
238 mutex_unlock(&dev->desc->ibi_lock);
239 }
240 i3c_bus_normaluse_unlock(dev->bus);
241}
242EXPORT_SYMBOL_GPL(i3c_device_free_ibi);
243
244/**
245 * i3cdev_to_dev() - Returns the device embedded in @i3cdev
246 * @i3cdev: I3C device
247 *
248 * Return: a pointer to a device object.
249 */
250struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
251{
252 return &i3cdev->dev;
253}
254EXPORT_SYMBOL_GPL(i3cdev_to_dev);
255
256/**
257 * i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
258 * @i3cdev: I3C device
259 * @id_table: I3C device match table
260 *
261 * Return: a pointer to an i3c_device_id object or NULL if there's no match.
262 */
263const struct i3c_device_id *
264i3c_device_match_id(struct i3c_device *i3cdev,
265 const struct i3c_device_id *id_table)
266{
267 struct i3c_device_info devinfo;
268 const struct i3c_device_id *id;
269 u16 manuf, part, ext_info;
270 bool rndpid;
271
272 i3c_device_get_info(i3cdev, &devinfo);
273
274 manuf = I3C_PID_MANUF_ID(devinfo.pid);
275 part = I3C_PID_PART_ID(devinfo.pid);
276 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
277 rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
278
279 for (id = id_table; id->match_flags != 0; id++) {
280 if ((id->match_flags & I3C_MATCH_DCR) &&
281 id->dcr != devinfo.dcr)
282 continue;
283
284 if ((id->match_flags & I3C_MATCH_MANUF) &&
285 id->manuf_id != manuf)
286 continue;
287
288 if ((id->match_flags & I3C_MATCH_PART) &&
289 (rndpid || id->part_id != part))
290 continue;
291
292 if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
293 (rndpid || id->extra_info != ext_info))
294 continue;
295
296 return id;
297 }
298
299 return NULL;
300}
301EXPORT_SYMBOL_GPL(i3c_device_match_id);
302
303/**
304 * i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
305 * connected master controller.
306 * @dev: I3C device
307 *
308 * Return: a bit mask, which supported transfer mode, bit position is defined at
309 * enum i3c_hdr_mode
310 */
311u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
312{
313 return i3c_bus_to_i3c_master(dev->bus)->this->info.hdr_cap | BIT(I3C_SDR);
314}
315EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
316
317/**
318 * i3c_driver_register_with_owner() - register an I3C device driver
319 *
320 * @drv: driver to register
321 * @owner: module that owns this driver
322 *
323 * Register @drv to the core.
324 *
325 * Return: 0 in case of success, a negative error core otherwise.
326 */
327int i3c_driver_register_with_owner(struct i3c_driver *drv, struct module *owner)
328{
329 drv->driver.owner = owner;
330 drv->driver.bus = &i3c_bus_type;
331
332 if (!drv->probe) {
333 pr_err("Trying to register an i3c driver without probe callback\n");
334 return -EINVAL;
335 }
336
337 return driver_register(&drv->driver);
338}
339EXPORT_SYMBOL_GPL(i3c_driver_register_with_owner);
340
341/**
342 * i3c_driver_unregister() - unregister an I3C device driver
343 *
344 * @drv: driver to unregister
345 *
346 * Unregister @drv.
347 */
348void i3c_driver_unregister(struct i3c_driver *drv)
349{
350 driver_unregister(&drv->driver);
351}
352EXPORT_SYMBOL_GPL(i3c_driver_unregister);