~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 456eef7f2f319ec07132d9e567b2d958efe58013 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2013 Google, Inc
 *
 * (C) Copyright 2012
 * Pavel Herrmann <morpheus.ibis@gmail.com>
 */

#ifndef _DM_UCLASS_H
#define _DM_UCLASS_H

#include <dm/ofnode.h>
#include <dm/uclass-id.h>
#include <linker_lists.h>
#include <linux/list.h>

/**
 * struct uclass - a U-Boot drive class, collecting together similar drivers
 *
 * A uclass provides an interface to a particular function, which is
 * implemented by one or more drivers. Every driver belongs to a uclass even
 * if it is the only driver in that uclass. An example uclass is GPIO, which
 * provides the ability to change read inputs, set and clear outputs, etc.
 * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and
 * PMIC IO lines, all made available in a unified way through the uclass.
 *
 * @priv_: Private data for this uclass (do not access outside driver model)
 * @uc_drv: The driver for the uclass itself, not to be confused with a
 * 'struct driver'
 * @dev_head: List of devices in this uclass (devices are attached to their
 * uclass when their bind method is called)
 * @sibling_node: Next uclass in the linked list of uclasses
 */
struct uclass {
	void *priv_;
	struct uclass_driver *uc_drv;
	struct list_head dev_head;
	struct list_head sibling_node;
};

struct driver;
struct udevice;

/* Members of this uclass sequence themselves with aliases */
#define DM_UC_FLAG_SEQ_ALIAS			(1 << 0)

/* Members of this uclass without aliases don't get a sequence number */
#define DM_UC_FLAG_NO_AUTO_SEQ			(1 << 1)

/* Same as DM_FLAG_ALLOC_PRIV_DMA */
#define DM_UC_FLAG_ALLOC_PRIV_DMA		(1 << 5)

/**
 * struct uclass_driver - Driver for the uclass
 *
 * A uclass_driver provides a consistent interface to a set of related
 * drivers.
 *
 * @name: Name of uclass driver
 * @id: ID number of this uclass
 * @post_bind: Called after a new device is bound to this uclass
 * @pre_unbind: Called before a device is unbound from this uclass
 * @pre_probe: Called before a new device is probed
 * @post_probe: Called after a new device is probed
 * @pre_remove: Called before a device is removed
 * @child_post_bind: Called after a child is bound to a device in this uclass
 * @child_pre_probe: Called before a child in this uclass is probed
 * @child_post_probe: Called after a child in this uclass is probed
 * @init: Called to set up the uclass
 * @destroy: Called to destroy the uclass
 * @priv_auto: If non-zero this is the size of the private data
 * to be allocated in the uclass's ->priv pointer. If zero, then the uclass
 * driver is responsible for allocating any data required.
 * @per_device_auto: Each device can hold private data owned
 * by the uclass. If required this will be automatically allocated if this
 * value is non-zero.
 * @per_device_plat_auto: Each device can hold platform data
 * owned by the uclass as 'dev->uclass_plat'. If the value is non-zero,
 * then this will be automatically allocated.
 * @per_child_auto: Each child device (of a parent in this
 * uclass) can hold parent data for the device/uclass. This value is only
 * used as a fallback if this member is 0 in the driver.
 * @per_child_plat_auto: A bus likes to store information about
 * its children. If non-zero this is the size of this data, to be allocated
 * in the child device's parent_plat pointer. This value is only used as
 * a fallback if this member is 0 in the driver.
 * @flags: Flags for this uclass ``(DM_UC_...)``
 */
struct uclass_driver {
	const char *name;
	enum uclass_id id;
	int (*post_bind)(struct udevice *dev);
	int (*pre_unbind)(struct udevice *dev);
	int (*pre_probe)(struct udevice *dev);
	int (*post_probe)(struct udevice *dev);
	int (*pre_remove)(struct udevice *dev);
	int (*child_post_bind)(struct udevice *dev);
	int (*child_pre_probe)(struct udevice *dev);
	int (*child_post_probe)(struct udevice *dev);
	int (*init)(struct uclass *class);
	int (*destroy)(struct uclass *class);
	int priv_auto;
	int per_device_auto;
	int per_device_plat_auto;
	int per_child_auto;
	int per_child_plat_auto;
	uint32_t flags;
};

/* Declare a new uclass_driver */
#define UCLASS_DRIVER(__name)						\
	ll_entry_declare(struct uclass_driver, __name, uclass_driver)

/*
 * These two macros DM_UCLASS_DRIVER_REF and DM_UCLASS_DRIVER_REF are only
 * allowed in code generated by dtoc, because the ordering is important and if
 * other instances creep in then they may mess up the ordering expected by dtoc.
 *
 * It is OK to use them with 'extern' though, since that does not actually
 * add a new record to the linker_list.
 */

/**
 * DM_UCLASS_DRIVER_REF() - Get a reference to a uclass driver
 *
 * This is useful in data structures and code for referencing a uclass_driver at
 * build time. Before this is used, an extern UCLASS_DRIVER() must have been
 * declared.
 *
 * For example::
 *
 *   extern UCLASS_DRIVER(clk);
 *   struct uclass_driver *drvs[] = {
 *       DM_UCLASS_DRIVER_REF(clk),
 *   };
 *
 * @_name: Name of the uclass_driver. This must be a valid C identifier, used by
 *	the linker_list.
 * Return: struct uclass_driver * for the uclass driver
 */
#define DM_UCLASS_DRIVER_REF(_name)					\
	ll_entry_ref(struct uclass_driver, _name, uclass_driver)

/**
 * uclass_get_priv() - Get the private data for a uclass
 *
 * @uc:	Uclass to check
 * Return: private data, or NULL if none
 */
void *uclass_get_priv(const struct uclass *uc);

/**
 * uclass_get() - Get a uclass based on an ID, creating it if needed
 *
 * Every uclass is identified by an ID, a number from 0 to n-1 where n is
 * the number of uclasses. This function allows looking up a uclass by its
 * ID.
 *
 * @key: ID to look up
 * @ucp: Returns pointer to uclass (there is only one per ID)
 * Return:
 * 0 if OK, -EDEADLK if driver model is not yet inited,
 * other -ve on other error
 */
int uclass_get(enum uclass_id key, struct uclass **ucp);

/**
 * uclass_get_name() - Get the name of a uclass driver
 *
 * @id: ID to look up
 * Return: the name of the uclass driver for that ID, or NULL if none
 */
const char *uclass_get_name(enum uclass_id id);

/**
 * uclass_get_by_namelen() - Look up a uclass by its driver name
 *
 * @name: Name to look up
 * @len: Length of @name (the uclass driver name must have the same length)
 * Return: the associated uclass ID, or UCLASS_INVALID if not found
 */
enum uclass_id uclass_get_by_namelen(const char *name, int len);

/**
 * uclass_get_by_name() - Look up a uclass by its driver name
 *
 * @name: Name to look up
 * Return: the associated uclass ID, or UCLASS_INVALID if not found
 */
enum uclass_id uclass_get_by_name(const char *name);

/**
 * uclass_get_device() - Get a uclass device based on an ID and index
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @index: Device number within that uclass (0=first)
 * @devp: Returns pointer to device (there is only one per for each ID)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);

/**
 * uclass_get_device_by_name() - Get a uclass device by its name
 *
 * This searches the devices in the uclass for one with the exactly given name.
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @name: name of a device to get
 * @devp: Returns pointer to device (the first one with the name)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_name(enum uclass_id id, const char *name,
			      struct udevice **devp);

/**
 * uclass_get_device_by_seq() - Get a uclass device based on an ID and sequence
 *
 * If an active device has this sequence it will be returned. If there is no
 * such device then this will check for a device that is requesting this
 * sequence.
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @seq: Sequence number to find (0=first)
 * @devp: Returns pointer to device (there is only one for each seq)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);

/**
 * uclass_get_device_by_of_offset() - Get a uclass device by device tree node
 *
 * This searches the devices in the uclass for one attached to the given
 * device tree node.
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @node: Device tree offset to search for (if -ve then -ENODEV is returned)
 * @devp: Returns pointer to device (there is only one for each node)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_of_offset(enum uclass_id id, int node,
				   struct udevice **devp);

/**
 * uclass_get_device_by_ofnode() - Get a uclass device by device tree node
 *
 * This searches the devices in the uclass for one attached to the given
 * device tree node.
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @node: Device tree node to search for (if NULL then -ENODEV is returned)
 * @devp: Returns pointer to device (there is only one for each node)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
				struct udevice **devp);

/**
 * uclass_get_device_by_of_path() - Get a uclass device by device tree path
 *
 * This searches the devices in the uclass for one attached to the
 * device tree node corresponding to the given path (which may also be
 * an alias).
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @path: Device tree path to search for (if no such path then -ENODEV is returned)
 * @devp: Returns pointer to device (there is only one for each node)
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_of_path(enum uclass_id id, const char *path,
				 struct udevice **devp);

/**
 * uclass_get_device_by_phandle_id() - Get a uclass device by phandle id
 *
 * This searches the devices in the uclass for one with the given phandle id.
 *
 * The device is probed to activate it ready for use.
 *
 * @id:		uclass ID to look up
 * @phandle_id: the phandle id to look up
 * @devp:	Returns pointer to device (there is only one for each node).
 *		NULL if there is no such device.
 * Return:
 * 0 if OK, -ENODEV if there is no device match the phandle,
 * other -ve on error
 */
int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
				    struct udevice **devp);

/**
 * uclass_get_device_by_phandle() - Get a uclass device by phandle
 *
 * This searches the devices in the uclass for one with the given phandle.
 *
 * The device is probed to activate it ready for use.
 *
 * @id: uclass ID to look up
 * @parent: Parent device containing the phandle pointer
 * @name: Name of property in the parent device node
 * @devp: Returns pointer to device (there is only one for each node)
 * Return: 0 if OK, -ENOENT if there is no @name present in the node, other
 * -ve on error
 */
int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
				 const char *name, struct udevice **devp);

/**
 * uclass_get_device_by_driver() - Get a uclass device for a driver
 *
 * This searches the devices in the uclass for one that uses the given
 * driver. Use DM_DRIVER_GET(name) for the @drv argument, where 'name' is
 * the driver name - as used in U_BOOT_DRIVER(name).
 *
 * The device is probed to activate it ready for use.
 *
 * @id: ID to look up
 * @drv: Driver to look for
 * @devp: Returns pointer to the first device with that driver
 * Return: 0 if OK, -ve on error
 */
int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
				struct udevice **devp);

/**
 * uclass_first_device() - Get the first device in a uclass
 *
 * The device returned is probed if necessary, and ready for use
 * Devices that fail to probe are skipped
 *
 * This function is useful to start iterating through a list of devices which
 * are functioning correctly and can be probed.
 *
 * @id: Uclass ID to look up
 * @devp: Returns pointer to the first device in that uclass if no error
 * occurred, or NULL if there is no usable device
 */
void uclass_first_device(enum uclass_id id, struct udevice **devp);

/**
 * uclass_next_device() - Get the next device in a uclass
 *
 * The device returned is probed if necessary, and ready for use
 * Devices that fail to probe are skipped
 *
 * This function is useful to iterate through a list of devices which
 * are functioning correctly and can be probed.
 *
 * @devp: On entry, pointer to device to lookup. On exit, returns pointer
 * to the next device in the uclass if no error occurred, or NULL if there is
 * no next device
 */
void uclass_next_device(struct udevice **devp);

/**
 * uclass_first_device_err() - Get the first device in a uclass
 *
 * The device returned is probed if necessary, and ready for use if no error is
 * returned
 *
 * @id: Uclass ID to look up
 * @devp: Returns pointer to the first device in that uclass, or NULL if none
 * Return: 0 if found, -ENODEV if not found, other -ve on error
 */
int uclass_first_device_err(enum uclass_id id, struct udevice **devp);

/**
 * uclass_next_device_err() - Get the next device in a uclass
 *
 * The device returned is probed if necessary, and ready for use if no error is
 * returned
 *
 * @devp: On entry, pointer to device to lookup. On exit, returns pointer
 * to the next device in the uclass if no error occurred, or NULL if
 * there is no next device.
 * Return: 0 if found, -ENODEV if not found, other -ve on error
 */
int uclass_next_device_err(struct udevice **devp);

/**
 * uclass_first_device_check() - Get the first device in a uclass
 *
 * The device returned is probed if necessary, and ready for use if no error is
 * returned
 *
 * This function is useful to start iterating through a list of devices which
 * are functioning correctly and can be probed.
 *
 * @id: Uclass ID to look up
 * @devp: Returns pointer to the first device in that uclass, or NULL if there
 * is no first device
 * Return: 0 if OK (found or not found), other -ve on error. If an error occurs
 * it is still possible to move to the next device.
 */
int uclass_first_device_check(enum uclass_id id, struct udevice **devp);

/**
 * uclass_next_device_check() - Get the next device in a uclass
 *
 * The device returned is probed if necessary, and ready for use if no error is
 * returned
 *
 * This function is useful to start iterating through a list of devices which
 * are functioning correctly and can be probed.
 *
 * @devp: On entry, pointer to device to lookup. On exit, returns pointer
 * to the next device in the uclass if any
 * Return: 0 if OK (found or not found), other -ve on error. If an error occurs
 * it is still possible to move to the next device.
 */
int uclass_next_device_check(struct udevice **devp);

/**
 * uclass_first_device_drvdata() - Find the first device with given driver data
 *
 * This searches through the devices for a particular uclass looking for one
 * that has the given driver data.
 *
 * @id: Uclass ID to check
 * @driver_data: Driver data to search for
 * @devp: Returns pointer to the first matching device in that uclass, if found
 * Return: 0 if found, -ENODEV if not found, other -ve on error
 */
int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
				struct udevice **devp);

/**
 * uclass_probe_all() - Probe all devices based on an uclass ID
 *
 * This function probes all devices associated with a uclass by
 * looking for its ID.
 *
 * @id: uclass ID to look up
 * Return: 0 if OK, other -ve on error
 */
int uclass_probe_all(enum uclass_id id);

/**
 * uclass_id_count() - Count the number of devices in a uclass
 *
 * @id: uclass ID to look up
 * Return: number of devices in that uclass (0 if none)
 */
int uclass_id_count(enum uclass_id id);

/**
 * uclass_id_foreach_dev() - iterate through devices of a given uclass ID
 *
 * This creates a for() loop which works through the available devices in
 * a uclass ID in order from start to end.
 *
 * If for some reason the uclass cannot be found, this does nothing.
 *
 * @id: enum uclass_id ID to use
 * @pos: struct udevice * to hold the current device. Set to NULL when there
 * are no more devices.
 * @uc: temporary uclass variable (``struct uclass *``)
 */
#define uclass_id_foreach_dev(id, pos, uc) \
	if (!uclass_get(id, &uc)) \
		list_for_each_entry(pos, &uc->dev_head, uclass_node)

/**
 * uclass_foreach_dev() - iterate through devices of a given uclass
 *
 * This creates a for() loop which works through the available devices in
 * a uclass in order from start to end.
 *
 * @pos: struct udevice * to hold the current device. Set to NULL when there
 * are no more devices.
 * @uc: uclass to scan (`struct uclass *`)
 */
#define uclass_foreach_dev(pos, uc)	\
	list_for_each_entry(pos, &uc->dev_head, uclass_node)

/**
 * uclass_foreach_dev_safe() - safely iterate through devices of a given uclass
 *
 * This creates a for() loop which works through the available devices in
 * a uclass in order from start to end. Inside the loop, it is safe to remove
 * @pos if required.
 *
 * @pos: struct udevice * to hold the current device. Set to NULL when there
 * are no more devices.
 * @next: struct udevice * to hold the next next
 * @uc: uclass to scan (`struct uclass *`)
 */
#define uclass_foreach_dev_safe(pos, next, uc)	\
	list_for_each_entry_safe(pos, next, &uc->dev_head, uclass_node)

/**
 * uclass_foreach_dev_probe() - iterate through devices of a given uclass ID
 *
 * This creates a for() loop which works through the available devices in
 * a uclass in order from start to end. Devices are probed if necessary,
 * and ready for use.
 *
 * @id: Uclass ID
 * @dev: struct udevice * to hold the current device. Set to NULL when there
 * are no more devices.
 */
#define uclass_foreach_dev_probe(id, dev)	\
	for (uclass_first_device(id, &dev); dev; \
	     uclass_next_device(&dev))

#endif