xref: /OK3568_Linux_fs/u-boot/drivers/core/uclass.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2013 Google, Inc
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2012
5*4882a593Smuzhiyun  * Pavel Herrmann <morpheus.ibis@gmail.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <dm.h>
12*4882a593Smuzhiyun #include <errno.h>
13*4882a593Smuzhiyun #include <malloc.h>
14*4882a593Smuzhiyun #include <dm/device.h>
15*4882a593Smuzhiyun #include <dm/device-internal.h>
16*4882a593Smuzhiyun #include <dm/lists.h>
17*4882a593Smuzhiyun #include <dm/uclass.h>
18*4882a593Smuzhiyun #include <dm/uclass-internal.h>
19*4882a593Smuzhiyun #include <dm/util.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
22*4882a593Smuzhiyun 
uclass_find(enum uclass_id key)23*4882a593Smuzhiyun struct uclass *uclass_find(enum uclass_id key)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	struct uclass *uc;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	if (!gd->dm_root)
28*4882a593Smuzhiyun 		return NULL;
29*4882a593Smuzhiyun 	/*
30*4882a593Smuzhiyun 	 * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
31*4882a593Smuzhiyun 	 * node to the start of the list, or creating a linear array mapping
32*4882a593Smuzhiyun 	 * id to node.
33*4882a593Smuzhiyun 	 */
34*4882a593Smuzhiyun 	list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
35*4882a593Smuzhiyun 		if (uc->uc_drv->id == key)
36*4882a593Smuzhiyun 			return uc;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 		if (uc->uc_drv->id == UCLASS_ROOT)
39*4882a593Smuzhiyun 			break;
40*4882a593Smuzhiyun 	}
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return NULL;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /**
46*4882a593Smuzhiyun  * uclass_add() - Create new uclass in list
47*4882a593Smuzhiyun  * @id: Id number to create
48*4882a593Smuzhiyun  * @ucp: Returns pointer to uclass, or NULL on error
49*4882a593Smuzhiyun  * @return 0 on success, -ve on error
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * The new uclass is added to the list. There must be only one uclass for
52*4882a593Smuzhiyun  * each id.
53*4882a593Smuzhiyun  */
uclass_add(enum uclass_id id,struct uclass ** ucp)54*4882a593Smuzhiyun static int uclass_add(enum uclass_id id, struct uclass **ucp)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct uclass_driver *uc_drv;
57*4882a593Smuzhiyun 	struct uclass *uc;
58*4882a593Smuzhiyun 	int ret;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	*ucp = NULL;
61*4882a593Smuzhiyun 	uc_drv = lists_uclass_lookup(id);
62*4882a593Smuzhiyun 	if (!uc_drv) {
63*4882a593Smuzhiyun 		debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
64*4882a593Smuzhiyun 		      id);
65*4882a593Smuzhiyun 		/*
66*4882a593Smuzhiyun 		 * Use a strange error to make this case easier to find. When
67*4882a593Smuzhiyun 		 * a uclass is not available it can prevent driver model from
68*4882a593Smuzhiyun 		 * starting up and this failure is otherwise hard to debug.
69*4882a593Smuzhiyun 		 */
70*4882a593Smuzhiyun 		return -EPFNOSUPPORT;
71*4882a593Smuzhiyun 	}
72*4882a593Smuzhiyun 	uc = calloc(1, sizeof(*uc));
73*4882a593Smuzhiyun 	if (!uc)
74*4882a593Smuzhiyun 		return -ENOMEM;
75*4882a593Smuzhiyun 	if (uc_drv->priv_auto_alloc_size) {
76*4882a593Smuzhiyun 		uc->priv = calloc(1, uc_drv->priv_auto_alloc_size);
77*4882a593Smuzhiyun 		if (!uc->priv) {
78*4882a593Smuzhiyun 			ret = -ENOMEM;
79*4882a593Smuzhiyun 			goto fail_mem;
80*4882a593Smuzhiyun 		}
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 	uc->uc_drv = uc_drv;
83*4882a593Smuzhiyun #ifdef CONFIG_USING_KERNEL_DTB_V2
84*4882a593Smuzhiyun 	uc->u_boot_dev_head = NULL;
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun 	INIT_LIST_HEAD(&uc->sibling_node);
87*4882a593Smuzhiyun 	INIT_LIST_HEAD(&uc->dev_head);
88*4882a593Smuzhiyun 	list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (uc_drv->init) {
91*4882a593Smuzhiyun 		ret = uc_drv->init(uc);
92*4882a593Smuzhiyun 		if (ret)
93*4882a593Smuzhiyun 			goto fail;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	*ucp = uc;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	return 0;
99*4882a593Smuzhiyun fail:
100*4882a593Smuzhiyun 	if (uc_drv->priv_auto_alloc_size) {
101*4882a593Smuzhiyun 		free(uc->priv);
102*4882a593Smuzhiyun 		uc->priv = NULL;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	list_del(&uc->sibling_node);
105*4882a593Smuzhiyun fail_mem:
106*4882a593Smuzhiyun 	free(uc);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return ret;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
uclass_destroy(struct uclass * uc)111*4882a593Smuzhiyun int uclass_destroy(struct uclass *uc)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct uclass_driver *uc_drv;
114*4882a593Smuzhiyun 	struct udevice *dev;
115*4882a593Smuzhiyun 	int ret;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	/*
118*4882a593Smuzhiyun 	 * We cannot use list_for_each_entry_safe() here. If a device in this
119*4882a593Smuzhiyun 	 * uclass has a child device also in this uclass, it will be also be
120*4882a593Smuzhiyun 	 * unbound (by the recursion in the call to device_unbind() below).
121*4882a593Smuzhiyun 	 * We can loop until the list is empty.
122*4882a593Smuzhiyun 	 */
123*4882a593Smuzhiyun 	while (!list_empty(&uc->dev_head)) {
124*4882a593Smuzhiyun 		dev = list_first_entry(&uc->dev_head, struct udevice,
125*4882a593Smuzhiyun 				       uclass_node);
126*4882a593Smuzhiyun 		ret = device_remove(dev, DM_REMOVE_NORMAL);
127*4882a593Smuzhiyun 		if (ret)
128*4882a593Smuzhiyun 			return ret;
129*4882a593Smuzhiyun 		ret = device_unbind(dev);
130*4882a593Smuzhiyun 		if (ret)
131*4882a593Smuzhiyun 			return ret;
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	uc_drv = uc->uc_drv;
135*4882a593Smuzhiyun 	if (uc_drv->destroy)
136*4882a593Smuzhiyun 		uc_drv->destroy(uc);
137*4882a593Smuzhiyun 	list_del(&uc->sibling_node);
138*4882a593Smuzhiyun 	if (uc_drv->priv_auto_alloc_size)
139*4882a593Smuzhiyun 		free(uc->priv);
140*4882a593Smuzhiyun 	free(uc);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
uclass_get(enum uclass_id id,struct uclass ** ucp)145*4882a593Smuzhiyun int uclass_get(enum uclass_id id, struct uclass **ucp)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct uclass *uc;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	*ucp = NULL;
150*4882a593Smuzhiyun 	uc = uclass_find(id);
151*4882a593Smuzhiyun 	if (!uc)
152*4882a593Smuzhiyun 		return uclass_add(id, ucp);
153*4882a593Smuzhiyun 	*ucp = uc;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
uclass_get_name(enum uclass_id id)158*4882a593Smuzhiyun const char *uclass_get_name(enum uclass_id id)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	struct uclass *uc;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (uclass_get(id, &uc))
163*4882a593Smuzhiyun 		return NULL;
164*4882a593Smuzhiyun 	return uc->uc_drv->name;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
uclass_get_by_name(const char * name)167*4882a593Smuzhiyun enum uclass_id uclass_get_by_name(const char *name)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	int i;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	for (i = 0; i < UCLASS_COUNT; i++) {
172*4882a593Smuzhiyun 		struct uclass_driver *uc_drv = lists_uclass_lookup(i);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		if (uc_drv && !strcmp(uc_drv->name, name))
175*4882a593Smuzhiyun 			return i;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return UCLASS_INVALID;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
uclass_find_device(enum uclass_id id,int index,struct udevice ** devp)181*4882a593Smuzhiyun int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct uclass *uc;
184*4882a593Smuzhiyun 	struct udevice *dev;
185*4882a593Smuzhiyun 	int ret;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	*devp = NULL;
188*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
189*4882a593Smuzhiyun 	if (ret)
190*4882a593Smuzhiyun 		return ret;
191*4882a593Smuzhiyun 	if (list_empty(&uc->dev_head))
192*4882a593Smuzhiyun 		return -ENODEV;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
195*4882a593Smuzhiyun 		if (!index--) {
196*4882a593Smuzhiyun 			*devp = dev;
197*4882a593Smuzhiyun 			return 0;
198*4882a593Smuzhiyun 		}
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return -ENODEV;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
uclass_find_first_device(enum uclass_id id,struct udevice ** devp)204*4882a593Smuzhiyun int uclass_find_first_device(enum uclass_id id, struct udevice **devp)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	struct uclass *uc;
207*4882a593Smuzhiyun 	int ret;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	*devp = NULL;
210*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
211*4882a593Smuzhiyun 	if (ret)
212*4882a593Smuzhiyun 		return ret;
213*4882a593Smuzhiyun 	if (list_empty(&uc->dev_head))
214*4882a593Smuzhiyun 		return 0;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	*devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
uclass_find_next_device(struct udevice ** devp)221*4882a593Smuzhiyun int uclass_find_next_device(struct udevice **devp)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct udevice *dev = *devp;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	*devp = NULL;
226*4882a593Smuzhiyun 	if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
227*4882a593Smuzhiyun 		return 0;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	*devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
uclass_find_device_by_name(enum uclass_id id,const char * name,struct udevice ** devp)234*4882a593Smuzhiyun int uclass_find_device_by_name(enum uclass_id id, const char *name,
235*4882a593Smuzhiyun 			       struct udevice **devp)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct uclass *uc;
238*4882a593Smuzhiyun 	struct udevice *dev;
239*4882a593Smuzhiyun 	int ret;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	*devp = NULL;
242*4882a593Smuzhiyun 	if (!name)
243*4882a593Smuzhiyun 		return -EINVAL;
244*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
245*4882a593Smuzhiyun 	if (ret)
246*4882a593Smuzhiyun 		return ret;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
249*4882a593Smuzhiyun 		if (!strncmp(dev->name, name, strlen(name))) {
250*4882a593Smuzhiyun 			*devp = dev;
251*4882a593Smuzhiyun 			return 0;
252*4882a593Smuzhiyun 		}
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return -ENODEV;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
uclass_find_device_by_seq(enum uclass_id id,int seq_or_req_seq,bool find_req_seq,struct udevice ** devp)258*4882a593Smuzhiyun int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
259*4882a593Smuzhiyun 			      bool find_req_seq, struct udevice **devp)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	struct uclass *uc;
262*4882a593Smuzhiyun 	struct udevice *dev;
263*4882a593Smuzhiyun 	int ret;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	*devp = NULL;
266*4882a593Smuzhiyun 	pr_debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq);
267*4882a593Smuzhiyun 	if (seq_or_req_seq == -1)
268*4882a593Smuzhiyun 		return -ENODEV;
269*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
270*4882a593Smuzhiyun 	if (ret)
271*4882a593Smuzhiyun 		return ret;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
274*4882a593Smuzhiyun 		pr_debug("   - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name);
275*4882a593Smuzhiyun 		if ((find_req_seq ? dev->req_seq : dev->seq) ==
276*4882a593Smuzhiyun 				seq_or_req_seq) {
277*4882a593Smuzhiyun 			*devp = dev;
278*4882a593Smuzhiyun 			pr_debug("   - found\n");
279*4882a593Smuzhiyun 			return 0;
280*4882a593Smuzhiyun 		}
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 	pr_debug("   - not found\n");
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	return -ENODEV;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
uclass_find_device_by_of_offset(enum uclass_id id,int node,struct udevice ** devp)287*4882a593Smuzhiyun int uclass_find_device_by_of_offset(enum uclass_id id, int node,
288*4882a593Smuzhiyun 				    struct udevice **devp)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	struct uclass *uc;
291*4882a593Smuzhiyun 	struct udevice *dev;
292*4882a593Smuzhiyun 	int ret;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	*devp = NULL;
295*4882a593Smuzhiyun 	if (node < 0)
296*4882a593Smuzhiyun 		return -ENODEV;
297*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
298*4882a593Smuzhiyun 	if (ret)
299*4882a593Smuzhiyun 		return ret;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
302*4882a593Smuzhiyun 		if (dev_of_offset(dev) == node) {
303*4882a593Smuzhiyun 			*devp = dev;
304*4882a593Smuzhiyun 			return 0;
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return -ENODEV;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
uclass_find_device_by_ofnode(enum uclass_id id,ofnode node,struct udevice ** devp)311*4882a593Smuzhiyun int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
312*4882a593Smuzhiyun 				 struct udevice **devp)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	struct uclass *uc;
315*4882a593Smuzhiyun 	struct udevice *dev;
316*4882a593Smuzhiyun 	int ret;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	*devp = NULL;
319*4882a593Smuzhiyun 	if (!ofnode_valid(node))
320*4882a593Smuzhiyun 		return -ENODEV;
321*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
322*4882a593Smuzhiyun 	if (ret)
323*4882a593Smuzhiyun 		return ret;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
326*4882a593Smuzhiyun 		if (ofnode_equal(dev_ofnode(dev), node)) {
327*4882a593Smuzhiyun 			*devp = dev;
328*4882a593Smuzhiyun 			return 0;
329*4882a593Smuzhiyun 		}
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	return -ENODEV;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL)
uclass_find_device_by_phandle(enum uclass_id id,struct udevice * parent,const char * name,struct udevice ** devp)336*4882a593Smuzhiyun static int uclass_find_device_by_phandle(enum uclass_id id,
337*4882a593Smuzhiyun 					 struct udevice *parent,
338*4882a593Smuzhiyun 					 const char *name,
339*4882a593Smuzhiyun 					 struct udevice **devp)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	struct udevice *dev;
342*4882a593Smuzhiyun 	struct uclass *uc;
343*4882a593Smuzhiyun 	int find_phandle;
344*4882a593Smuzhiyun 	int ret;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	*devp = NULL;
347*4882a593Smuzhiyun 	find_phandle = dev_read_u32_default(parent, name, -1);
348*4882a593Smuzhiyun 	if (find_phandle <= 0)
349*4882a593Smuzhiyun 		return -ENOENT;
350*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
351*4882a593Smuzhiyun 	if (ret)
352*4882a593Smuzhiyun 		return ret;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
355*4882a593Smuzhiyun 		uint phandle;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		phandle = dev_read_phandle(dev);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		if (phandle == find_phandle) {
360*4882a593Smuzhiyun 			*devp = dev;
361*4882a593Smuzhiyun 			return 0;
362*4882a593Smuzhiyun 		}
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return -ENODEV;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun #endif
368*4882a593Smuzhiyun 
uclass_get_device_by_driver(enum uclass_id id,const struct driver * find_drv,struct udevice ** devp)369*4882a593Smuzhiyun int uclass_get_device_by_driver(enum uclass_id id,
370*4882a593Smuzhiyun 				const struct driver *find_drv,
371*4882a593Smuzhiyun 				struct udevice **devp)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct udevice *dev;
374*4882a593Smuzhiyun 	struct uclass *uc;
375*4882a593Smuzhiyun 	int ret;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
378*4882a593Smuzhiyun 	if (ret)
379*4882a593Smuzhiyun 		return ret;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
382*4882a593Smuzhiyun 		if (dev->driver == find_drv)
383*4882a593Smuzhiyun 			return uclass_get_device_tail(dev, 0, devp);
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	return -ENODEV;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
uclass_get_device_tail(struct udevice * dev,int ret,struct udevice ** devp)389*4882a593Smuzhiyun int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	if (ret)
392*4882a593Smuzhiyun 		return ret;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	assert(dev);
395*4882a593Smuzhiyun 	ret = device_probe(dev);
396*4882a593Smuzhiyun 	if (ret)
397*4882a593Smuzhiyun 		return ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	*devp = dev;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
uclass_get_device(enum uclass_id id,int index,struct udevice ** devp)404*4882a593Smuzhiyun int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	struct udevice *dev;
407*4882a593Smuzhiyun 	int ret;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	*devp = NULL;
410*4882a593Smuzhiyun 	ret = uclass_find_device(id, index, &dev);
411*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
uclass_get_device_by_name(enum uclass_id id,const char * name,struct udevice ** devp)414*4882a593Smuzhiyun int uclass_get_device_by_name(enum uclass_id id, const char *name,
415*4882a593Smuzhiyun 			      struct udevice **devp)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct udevice *dev;
418*4882a593Smuzhiyun 	int ret;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	*devp = NULL;
421*4882a593Smuzhiyun 	ret = uclass_find_device_by_name(id, name, &dev);
422*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
uclass_get_device_by_seq(enum uclass_id id,int seq,struct udevice ** devp)425*4882a593Smuzhiyun int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	struct udevice *dev;
428*4882a593Smuzhiyun 	int ret;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	*devp = NULL;
431*4882a593Smuzhiyun 	ret = uclass_find_device_by_seq(id, seq, false, &dev);
432*4882a593Smuzhiyun 	if (ret == -ENODEV) {
433*4882a593Smuzhiyun 		/*
434*4882a593Smuzhiyun 		 * We didn't find it in probed devices. See if there is one
435*4882a593Smuzhiyun 		 * that will request this seq if probed.
436*4882a593Smuzhiyun 		 */
437*4882a593Smuzhiyun 		ret = uclass_find_device_by_seq(id, seq, true, &dev);
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
uclass_get_device_by_of_offset(enum uclass_id id,int node,struct udevice ** devp)442*4882a593Smuzhiyun int uclass_get_device_by_of_offset(enum uclass_id id, int node,
443*4882a593Smuzhiyun 				   struct udevice **devp)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	struct udevice *dev;
446*4882a593Smuzhiyun 	int ret;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	*devp = NULL;
449*4882a593Smuzhiyun 	ret = uclass_find_device_by_of_offset(id, node, &dev);
450*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
uclass_get_device_by_ofnode(enum uclass_id id,ofnode node,struct udevice ** devp)453*4882a593Smuzhiyun int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
454*4882a593Smuzhiyun 				struct udevice **devp)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	struct udevice *dev;
457*4882a593Smuzhiyun 	int ret;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	*devp = NULL;
460*4882a593Smuzhiyun 	ret = uclass_find_device_by_ofnode(id, node, &dev);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL)
uclass_get_device_by_phandle_id(enum uclass_id id,uint phandle_id,struct udevice ** devp)466*4882a593Smuzhiyun int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
467*4882a593Smuzhiyun 				    struct udevice **devp)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun 	struct udevice *dev;
470*4882a593Smuzhiyun 	struct uclass *uc;
471*4882a593Smuzhiyun 	int ret;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	*devp = NULL;
474*4882a593Smuzhiyun 	ret = uclass_get(id, &uc);
475*4882a593Smuzhiyun 	if (ret)
476*4882a593Smuzhiyun 		return ret;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	ret = -ENODEV;
479*4882a593Smuzhiyun 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
480*4882a593Smuzhiyun 		uint phandle;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		phandle = dev_read_phandle(dev);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 		if (phandle == phandle_id) {
485*4882a593Smuzhiyun 			*devp = dev;
486*4882a593Smuzhiyun 			ret = 0;
487*4882a593Smuzhiyun 			break;
488*4882a593Smuzhiyun 		}
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
uclass_get_device_by_phandle(enum uclass_id id,struct udevice * parent,const char * name,struct udevice ** devp)494*4882a593Smuzhiyun int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
495*4882a593Smuzhiyun 				 const char *name, struct udevice **devp)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	struct udevice *dev;
498*4882a593Smuzhiyun 	int ret;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	*devp = NULL;
501*4882a593Smuzhiyun 	ret = uclass_find_device_by_phandle(id, parent, name, &dev);
502*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun #endif
505*4882a593Smuzhiyun 
uclass_first_device(enum uclass_id id,struct udevice ** devp)506*4882a593Smuzhiyun int uclass_first_device(enum uclass_id id, struct udevice **devp)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	struct udevice *dev;
509*4882a593Smuzhiyun 	int ret;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	*devp = NULL;
512*4882a593Smuzhiyun 	ret = uclass_find_first_device(id, &dev);
513*4882a593Smuzhiyun 	if (!dev)
514*4882a593Smuzhiyun 		return 0;
515*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
uclass_first_device_err(enum uclass_id id,struct udevice ** devp)518*4882a593Smuzhiyun int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	int ret;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	ret = uclass_first_device(id, devp);
523*4882a593Smuzhiyun 	if (ret)
524*4882a593Smuzhiyun 		return ret;
525*4882a593Smuzhiyun 	else if (!*devp)
526*4882a593Smuzhiyun 		return -ENODEV;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
uclass_next_device(struct udevice ** devp)531*4882a593Smuzhiyun int uclass_next_device(struct udevice **devp)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	struct udevice *dev = *devp;
534*4882a593Smuzhiyun 	int ret;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	*devp = NULL;
537*4882a593Smuzhiyun 	ret = uclass_find_next_device(&dev);
538*4882a593Smuzhiyun 	if (!dev)
539*4882a593Smuzhiyun 		return 0;
540*4882a593Smuzhiyun 	return uclass_get_device_tail(dev, ret, devp);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
uclass_first_device_check(enum uclass_id id,struct udevice ** devp)543*4882a593Smuzhiyun int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	int ret;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	*devp = NULL;
548*4882a593Smuzhiyun 	ret = uclass_find_first_device(id, devp);
549*4882a593Smuzhiyun 	if (ret)
550*4882a593Smuzhiyun 		return ret;
551*4882a593Smuzhiyun 	if (!*devp)
552*4882a593Smuzhiyun 		return 0;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return device_probe(*devp);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
uclass_next_device_check(struct udevice ** devp)557*4882a593Smuzhiyun int uclass_next_device_check(struct udevice **devp)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	int ret;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	ret = uclass_find_next_device(devp);
562*4882a593Smuzhiyun 	if (ret)
563*4882a593Smuzhiyun 		return ret;
564*4882a593Smuzhiyun 	if (!*devp)
565*4882a593Smuzhiyun 		return 0;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	return device_probe(*devp);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
uclass_bind_device(struct udevice * dev,bool after_u_boot_dev)570*4882a593Smuzhiyun int uclass_bind_device(struct udevice *dev, bool after_u_boot_dev)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	struct uclass *uc;
573*4882a593Smuzhiyun 	int ret;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	uc = dev->uclass;
576*4882a593Smuzhiyun #ifdef CONFIG_USING_KERNEL_DTB_V2
577*4882a593Smuzhiyun 	if (after_u_boot_dev)
578*4882a593Smuzhiyun 		list_add_tail(&dev->uclass_node, &uc->dev_head);
579*4882a593Smuzhiyun 	else
580*4882a593Smuzhiyun 		list_add_tail(&dev->uclass_node, uc->u_boot_dev_head);
581*4882a593Smuzhiyun #else
582*4882a593Smuzhiyun 	list_add_tail(&dev->uclass_node, &uc->dev_head);
583*4882a593Smuzhiyun #endif
584*4882a593Smuzhiyun 	if (dev->parent) {
585*4882a593Smuzhiyun 		struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 		if (uc_drv->child_post_bind) {
588*4882a593Smuzhiyun 			ret = uc_drv->child_post_bind(dev);
589*4882a593Smuzhiyun 			if (ret)
590*4882a593Smuzhiyun 				goto err;
591*4882a593Smuzhiyun 		}
592*4882a593Smuzhiyun 	}
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	return 0;
595*4882a593Smuzhiyun err:
596*4882a593Smuzhiyun 	/* There is no need to undo the parent's post_bind call */
597*4882a593Smuzhiyun 	list_del(&dev->uclass_node);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	return ret;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
uclass_unbind_device(struct udevice * dev)603*4882a593Smuzhiyun int uclass_unbind_device(struct udevice *dev)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	struct uclass *uc;
606*4882a593Smuzhiyun 	int ret;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	uc = dev->uclass;
609*4882a593Smuzhiyun 	if (uc->uc_drv->pre_unbind) {
610*4882a593Smuzhiyun 		ret = uc->uc_drv->pre_unbind(dev);
611*4882a593Smuzhiyun 		if (ret)
612*4882a593Smuzhiyun 			return ret;
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	list_del(&dev->uclass_node);
616*4882a593Smuzhiyun 	return 0;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun #endif
619*4882a593Smuzhiyun 
uclass_resolve_seq(struct udevice * dev)620*4882a593Smuzhiyun int uclass_resolve_seq(struct udevice *dev)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	struct udevice *dup;
623*4882a593Smuzhiyun 	int seq;
624*4882a593Smuzhiyun 	int ret;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	assert(dev->seq == -1);
627*4882a593Smuzhiyun 	ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq,
628*4882a593Smuzhiyun 					false, &dup);
629*4882a593Smuzhiyun 	if (!ret) {
630*4882a593Smuzhiyun 		dm_warn("Device '%s': seq %d is in use by '%s'\n",
631*4882a593Smuzhiyun 			dev->name, dev->req_seq, dup->name);
632*4882a593Smuzhiyun 	} else if (ret == -ENODEV) {
633*4882a593Smuzhiyun 		/* Our requested sequence number is available */
634*4882a593Smuzhiyun 		if (dev->req_seq != -1)
635*4882a593Smuzhiyun 			return dev->req_seq;
636*4882a593Smuzhiyun 	} else {
637*4882a593Smuzhiyun 		return ret;
638*4882a593Smuzhiyun 	}
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	for (seq = 0; seq < DM_MAX_SEQ; seq++) {
641*4882a593Smuzhiyun 		ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq,
642*4882a593Smuzhiyun 						false, &dup);
643*4882a593Smuzhiyun 		if (ret == -ENODEV)
644*4882a593Smuzhiyun 			break;
645*4882a593Smuzhiyun 		if (ret)
646*4882a593Smuzhiyun 			return ret;
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 	return seq;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun 
uclass_pre_probe_device(struct udevice * dev)651*4882a593Smuzhiyun int uclass_pre_probe_device(struct udevice *dev)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	struct uclass_driver *uc_drv;
654*4882a593Smuzhiyun 	int ret;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	uc_drv = dev->uclass->uc_drv;
657*4882a593Smuzhiyun 	if (uc_drv->pre_probe) {
658*4882a593Smuzhiyun 		ret = uc_drv->pre_probe(dev);
659*4882a593Smuzhiyun 		if (ret)
660*4882a593Smuzhiyun 			return ret;
661*4882a593Smuzhiyun 	}
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	if (!dev->parent)
664*4882a593Smuzhiyun 		return 0;
665*4882a593Smuzhiyun 	uc_drv = dev->parent->uclass->uc_drv;
666*4882a593Smuzhiyun 	if (uc_drv->child_pre_probe)
667*4882a593Smuzhiyun 		return uc_drv->child_pre_probe(dev);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	return 0;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
uclass_post_probe_device(struct udevice * dev)672*4882a593Smuzhiyun int uclass_post_probe_device(struct udevice *dev)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun 	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (uc_drv->post_probe)
677*4882a593Smuzhiyun 		return uc_drv->post_probe(dev);
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	return 0;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
uclass_pre_remove_device(struct udevice * dev)683*4882a593Smuzhiyun int uclass_pre_remove_device(struct udevice *dev)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	struct uclass *uc;
686*4882a593Smuzhiyun 	int ret;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	uc = dev->uclass;
689*4882a593Smuzhiyun 	if (uc->uc_drv->pre_remove) {
690*4882a593Smuzhiyun 		ret = uc->uc_drv->pre_remove(dev);
691*4882a593Smuzhiyun 		if (ret)
692*4882a593Smuzhiyun 			return ret;
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return 0;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun #endif
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun UCLASS_DRIVER(nop) = {
700*4882a593Smuzhiyun 	.id		= UCLASS_NOP,
701*4882a593Smuzhiyun 	.name		= "nop",
702*4882a593Smuzhiyun };
703