Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sh/drivers/platform_early.c
26424 views
1
// SPDX--License-Identifier: GPL-2.0
2
3
#include <asm/platform_early.h>
4
#include <linux/mod_devicetable.h>
5
#include <linux/pm.h>
6
7
static __initdata LIST_HEAD(sh_early_platform_driver_list);
8
static __initdata LIST_HEAD(sh_early_platform_device_list);
9
10
static const struct platform_device_id *
11
platform_match_id(const struct platform_device_id *id,
12
struct platform_device *pdev)
13
{
14
while (id->name[0]) {
15
if (strcmp(pdev->name, id->name) == 0) {
16
pdev->id_entry = id;
17
return id;
18
}
19
id++;
20
}
21
return NULL;
22
}
23
24
static int platform_match(struct device *dev, struct device_driver *drv)
25
{
26
struct platform_device *pdev = to_platform_device(dev);
27
struct platform_driver *pdrv = to_platform_driver(drv);
28
29
/* When driver_override is set, only bind to the matching driver */
30
if (pdev->driver_override)
31
return !strcmp(pdev->driver_override, drv->name);
32
33
/* Then try to match against the id table */
34
if (pdrv->id_table)
35
return platform_match_id(pdrv->id_table, pdev) != NULL;
36
37
/* fall-back to driver name match */
38
return (strcmp(pdev->name, drv->name) == 0);
39
}
40
41
#ifdef CONFIG_PM
42
static void device_pm_init_common(struct device *dev)
43
{
44
if (!dev->power.early_init) {
45
spin_lock_init(&dev->power.lock);
46
dev->power.qos = NULL;
47
dev->power.early_init = true;
48
}
49
}
50
51
static void pm_runtime_early_init(struct device *dev)
52
{
53
dev->power.disable_depth = 1;
54
device_pm_init_common(dev);
55
}
56
#else
57
static void pm_runtime_early_init(struct device *dev) {}
58
#endif
59
60
/**
61
* sh_early_platform_driver_register - register early platform driver
62
* @epdrv: sh_early_platform driver structure
63
* @buf: string passed from early_param()
64
*
65
* Helper function for sh_early_platform_init() / sh_early_platform_init_buffer()
66
*/
67
int __init sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
68
char *buf)
69
{
70
char *tmp;
71
int n;
72
73
/* Simply add the driver to the end of the global list.
74
* Drivers will by default be put on the list in compiled-in order.
75
*/
76
if (!epdrv->list.next) {
77
INIT_LIST_HEAD(&epdrv->list);
78
list_add_tail(&epdrv->list, &sh_early_platform_driver_list);
79
}
80
81
/* If the user has specified device then make sure the driver
82
* gets prioritized. The driver of the last device specified on
83
* command line will be put first on the list.
84
*/
85
n = strlen(epdrv->pdrv->driver.name);
86
if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
87
list_move(&epdrv->list, &sh_early_platform_driver_list);
88
89
/* Allow passing parameters after device name */
90
if (buf[n] == '\0' || buf[n] == ',')
91
epdrv->requested_id = -1;
92
else {
93
epdrv->requested_id = simple_strtoul(&buf[n + 1],
94
&tmp, 10);
95
96
if (buf[n] != '.' || (tmp == &buf[n + 1])) {
97
epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
98
n = 0;
99
} else
100
n += strcspn(&buf[n + 1], ",") + 1;
101
}
102
103
if (buf[n] == ',')
104
n++;
105
106
if (epdrv->bufsize) {
107
memcpy(epdrv->buffer, &buf[n],
108
min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
109
epdrv->buffer[epdrv->bufsize - 1] = '\0';
110
}
111
}
112
113
return 0;
114
}
115
116
/**
117
* sh_early_platform_add_devices - adds a number of early platform devices
118
* @devs: array of early platform devices to add
119
* @num: number of early platform devices in array
120
*
121
* Used by early architecture code to register early platform devices and
122
* their platform data.
123
*/
124
void __init sh_early_platform_add_devices(struct platform_device **devs, int num)
125
{
126
struct device *dev;
127
int i;
128
129
/* simply add the devices to list */
130
for (i = 0; i < num; i++) {
131
dev = &devs[i]->dev;
132
133
if (!dev->devres_head.next) {
134
pm_runtime_early_init(dev);
135
INIT_LIST_HEAD(&dev->devres_head);
136
list_add_tail(&dev->devres_head,
137
&sh_early_platform_device_list);
138
}
139
}
140
}
141
142
/**
143
* sh_early_platform_driver_register_all - register early platform drivers
144
* @class_str: string to identify early platform driver class
145
*
146
* Used by architecture code to register all early platform drivers
147
* for a certain class. If omitted then only early platform drivers
148
* with matching kernel command line class parameters will be registered.
149
*/
150
void __init sh_early_platform_driver_register_all(char *class_str)
151
{
152
/* The "class_str" parameter may or may not be present on the kernel
153
* command line. If it is present then there may be more than one
154
* matching parameter.
155
*
156
* Since we register our early platform drivers using early_param()
157
* we need to make sure that they also get registered in the case
158
* when the parameter is missing from the kernel command line.
159
*
160
* We use parse_early_options() to make sure the early_param() gets
161
* called at least once. The early_param() may be called more than
162
* once since the name of the preferred device may be specified on
163
* the kernel command line. sh_early_platform_driver_register() handles
164
* this case for us.
165
*/
166
parse_early_options(class_str);
167
}
168
169
/**
170
* sh_early_platform_match - find early platform device matching driver
171
* @epdrv: early platform driver structure
172
* @id: id to match against
173
*/
174
static struct platform_device * __init
175
sh_early_platform_match(struct sh_early_platform_driver *epdrv, int id)
176
{
177
struct platform_device *pd;
178
179
list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
180
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
181
if (pd->id == id)
182
return pd;
183
184
return NULL;
185
}
186
187
/**
188
* sh_early_platform_left - check if early platform driver has matching devices
189
* @epdrv: early platform driver structure
190
* @id: return true if id or above exists
191
*/
192
static int __init sh_early_platform_left(struct sh_early_platform_driver *epdrv,
193
int id)
194
{
195
struct platform_device *pd;
196
197
list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
198
if (platform_match(&pd->dev, &epdrv->pdrv->driver))
199
if (pd->id >= id)
200
return 1;
201
202
return 0;
203
}
204
205
/**
206
* sh_early_platform_driver_probe_id - probe drivers matching class_str and id
207
* @class_str: string to identify early platform driver class
208
* @id: id to match against
209
* @nr_probe: number of platform devices to successfully probe before exiting
210
*/
211
static int __init sh_early_platform_driver_probe_id(char *class_str,
212
int id,
213
int nr_probe)
214
{
215
struct sh_early_platform_driver *epdrv;
216
struct platform_device *match;
217
int match_id;
218
int n = 0;
219
int left = 0;
220
221
list_for_each_entry(epdrv, &sh_early_platform_driver_list, list) {
222
/* only use drivers matching our class_str */
223
if (strcmp(class_str, epdrv->class_str))
224
continue;
225
226
if (id == -2) {
227
match_id = epdrv->requested_id;
228
left = 1;
229
230
} else {
231
match_id = id;
232
left += sh_early_platform_left(epdrv, id);
233
234
/* skip requested id */
235
switch (epdrv->requested_id) {
236
case EARLY_PLATFORM_ID_ERROR:
237
case EARLY_PLATFORM_ID_UNSET:
238
break;
239
default:
240
if (epdrv->requested_id == id)
241
match_id = EARLY_PLATFORM_ID_UNSET;
242
}
243
}
244
245
switch (match_id) {
246
case EARLY_PLATFORM_ID_ERROR:
247
pr_warn("%s: unable to parse %s parameter\n",
248
class_str, epdrv->pdrv->driver.name);
249
fallthrough;
250
case EARLY_PLATFORM_ID_UNSET:
251
match = NULL;
252
break;
253
default:
254
match = sh_early_platform_match(epdrv, match_id);
255
}
256
257
if (match) {
258
/*
259
* Set up a sensible init_name to enable
260
* dev_name() and others to be used before the
261
* rest of the driver core is initialized.
262
*/
263
if (!match->dev.init_name && slab_is_available()) {
264
if (match->id != -1)
265
match->dev.init_name =
266
kasprintf(GFP_KERNEL, "%s.%d",
267
match->name,
268
match->id);
269
else
270
match->dev.init_name =
271
kasprintf(GFP_KERNEL, "%s",
272
match->name);
273
274
if (!match->dev.init_name)
275
return -ENOMEM;
276
}
277
278
if (epdrv->pdrv->probe(match))
279
pr_warn("%s: unable to probe %s early.\n",
280
class_str, match->name);
281
else
282
n++;
283
}
284
285
if (n >= nr_probe)
286
break;
287
}
288
289
if (left)
290
return n;
291
else
292
return -ENODEV;
293
}
294
295
/**
296
* sh_early_platform_driver_probe - probe a class of registered drivers
297
* @class_str: string to identify early platform driver class
298
* @nr_probe: number of platform devices to successfully probe before exiting
299
* @user_only: only probe user specified early platform devices
300
*
301
* Used by architecture code to probe registered early platform drivers
302
* within a certain class. For probe to happen a registered early platform
303
* device matching a registered early platform driver is needed.
304
*/
305
int __init sh_early_platform_driver_probe(char *class_str,
306
int nr_probe,
307
int user_only)
308
{
309
int k, n, i;
310
311
n = 0;
312
for (i = -2; n < nr_probe; i++) {
313
k = sh_early_platform_driver_probe_id(class_str, i, nr_probe - n);
314
315
if (k < 0)
316
break;
317
318
n += k;
319
320
if (user_only)
321
break;
322
}
323
324
return n;
325
}
326
327
/**
328
* early_platform_cleanup - clean up early platform code
329
*/
330
void __init early_platform_cleanup(void)
331
{
332
struct platform_device *pd, *pd2;
333
334
/* clean up the devres list used to chain devices */
335
list_for_each_entry_safe(pd, pd2, &sh_early_platform_device_list,
336
dev.devres_head) {
337
list_del(&pd->dev.devres_head);
338
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
339
}
340
}
341
342