Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae1d0a46 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'soc-device-match-tag1' of...

Merge tag 'soc-device-match-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into next/drivers

Pull "soc_device_match() interface for matching against soc_bus attributes"
from Geert Uytterhoeven:

This provides core infrastructure as a dependency for several users
(Freescale/NXP, Samsung, Renesas).

Its core parts have been acked by Greg, and the fixes by Arnd and/or
Greg (the last fix only received an informal ack, that's why I hadn't
added the ack).

This has already been pulled by Ulf, and is present in mmc/next, as a
dependency for a Freescale/NXP driver update.

* tag 'soc-device-match-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers:
  base: soc: Provide a dummy implementation of soc_device_match()
  base: soc: Check for NULL SoC device attributes
  base: soc: Introduce soc_device_match() interface
  base: soc: Early register bus when needed
parents d319fc6d da65a158
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE


config SOC_BUS
config SOC_BUS
	bool
	bool
	select GLOB


source "drivers/base/regmap/Kconfig"
source "drivers/base/regmap/Kconfig"


+79 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/glob.h>


static DEFINE_IDA(soc_ida);
static DEFINE_IDA(soc_ida);


@@ -113,6 +114,12 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
	struct soc_device *soc_dev;
	struct soc_device *soc_dev;
	int ret;
	int ret;


	if (!soc_bus_type.p) {
		ret = bus_register(&soc_bus_type);
		if (ret)
			goto out1;
	}

	soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
	soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
	if (!soc_dev) {
	if (!soc_dev) {
		ret = -ENOMEM;
		ret = -ENOMEM;
@@ -156,6 +163,78 @@ void soc_device_unregister(struct soc_device *soc_dev)


static int __init soc_bus_register(void)
static int __init soc_bus_register(void)
{
{
	if (soc_bus_type.p)
		return 0;

	return bus_register(&soc_bus_type);
	return bus_register(&soc_bus_type);
}
}
core_initcall(soc_bus_register);
core_initcall(soc_bus_register);

static int soc_device_match_one(struct device *dev, void *arg)
{
	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
	const struct soc_device_attribute *match = arg;

	if (match->machine &&
	    (!soc_dev->attr->machine ||
	     !glob_match(match->machine, soc_dev->attr->machine)))
		return 0;

	if (match->family &&
	    (!soc_dev->attr->family ||
	     !glob_match(match->family, soc_dev->attr->family)))
		return 0;

	if (match->revision &&
	    (!soc_dev->attr->revision ||
	     !glob_match(match->revision, soc_dev->attr->revision)))
		return 0;

	if (match->soc_id &&
	    (!soc_dev->attr->soc_id ||
	     !glob_match(match->soc_id, soc_dev->attr->soc_id)))
		return 0;

	return 1;
}

/*
 * soc_device_match - identify the SoC in the machine
 * @matches: zero-terminated array of possible matches
 *
 * returns the first matching entry of the argument array, or NULL
 * if none of them match.
 *
 * This function is meant as a helper in place of of_match_node()
 * in cases where either no device tree is available or the information
 * in a device node is insufficient to identify a particular variant
 * by its compatible strings or other properties. For new devices,
 * the DT binding should always provide unique compatible strings
 * that allow the use of of_match_node() instead.
 *
 * The calling function can use the .data entry of the
 * soc_device_attribute to pass a structure or function pointer for
 * each entry.
 */
const struct soc_device_attribute *soc_device_match(
	const struct soc_device_attribute *matches)
{
	int ret = 0;

	if (!matches)
		return NULL;

	while (!ret) {
		if (!(matches->machine || matches->family ||
		      matches->revision || matches->soc_id))
			break;
		ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
				       soc_device_match_one);
		if (!ret)
			matches++;
		else
			return matches;
	}
	return NULL;
}
EXPORT_SYMBOL_GPL(soc_device_match);
+9 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@ struct soc_device_attribute {
	const char *family;
	const char *family;
	const char *revision;
	const char *revision;
	const char *soc_id;
	const char *soc_id;
	const void *data;
};
};


/**
/**
@@ -34,4 +35,12 @@ void soc_device_unregister(struct soc_device *soc_dev);
 */
 */
struct device *soc_device_to_device(struct soc_device *soc);
struct device *soc_device_to_device(struct soc_device *soc);


#ifdef CONFIG_SOC_BUS
const struct soc_device_attribute *soc_device_match(
	const struct soc_device_attribute *matches);
#else
static inline const struct soc_device_attribute *soc_device_match(
	const struct soc_device_attribute *matches) { return NULL; }
#endif

#endif /* __SOC_BUS_H */
#endif /* __SOC_BUS_H */