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