Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
  7static __initdata LIST_HEAD(sh_early_platform_driver_list);
  8static __initdata LIST_HEAD(sh_early_platform_device_list);
  9
 10static const struct platform_device_id *
 11platform_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
 24static 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
 42static 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
 51static void pm_runtime_early_init(struct device *dev)
 52{
 53	dev->power.disable_depth = 1;
 54	device_pm_init_common(dev);
 55}
 56#else
 57static 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 */
 67int __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 */
124void __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 */
150void __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 */
174static struct platform_device * __init
175sh_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 */
192static 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 */
211static 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 */
305int __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 */
330void __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}