123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- From c97db7cc7778e34a53b42d58c766f0ec0e30d580 Mon Sep 17 00:00:00 2001
- From: Arnd Bergmann <[email protected]>
- Date: Wed, 21 Sep 2016 14:57:19 +0800
- Subject: [PATCH] base: soc: Introduce soc_device_match() interface
- We keep running into cases where device drivers want to know the exact
- version of the a SoC they are currently running on. In the past, this has
- usually been done through a vendor specific API that can be called by a
- driver, or by directly accessing some kind of version register that is
- not part of the device itself but that belongs to a global register area
- of the chip.
- Common reasons for doing this include:
- - A machine is not using devicetree or similar for passing data about
- on-chip devices, but just announces their presence using boot-time
- platform devices, and the machine code itself does not care about the
- revision.
- - There is existing firmware or boot loaders with existing DT binaries
- with generic compatible strings that do not identify the particular
- revision of each device, but the driver knows which SoC revisions
- include which part.
- - A prerelease version of a chip has some quirks and we are using the same
- version of the bootloader and the DT blob on both the prerelease and the
- final version. An update of the DT binding seems inappropriate because
- that would involve maintaining multiple copies of the dts and/or
- bootloader.
- This patch introduces the soc_device_match() interface that is meant to
- work like of_match_node() but instead of identifying the version of a
- device, it identifies the SoC itself using a vendor-agnostic interface.
- Unlike of_match_node(), we do not do an exact string compare but instead
- use glob_match() to allow wildcards in strings.
- Signed-off-by: Arnd Bergmann <[email protected]>
- Signed-off-by: Yangbo Lu <[email protected]>
- Signed-off-by: Geert Uytterhoeven <[email protected]>
- Acked-by: Greg Kroah-Hartman <[email protected]>
- ---
- drivers/base/Kconfig | 1 +
- drivers/base/soc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
- include/linux/sys_soc.h | 3 +++
- 3 files changed, 70 insertions(+)
- diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
- index fdf44cac08e6..991b21e1f89b 100644
- --- a/drivers/base/Kconfig
- +++ b/drivers/base/Kconfig
- @@ -235,6 +235,7 @@ config GENERIC_CPU_AUTOPROBE
-
- config SOC_BUS
- bool
- + select GLOB
-
- source "drivers/base/regmap/Kconfig"
-
- diff --git a/drivers/base/soc.c b/drivers/base/soc.c
- index 028cef377fd4..04ee597fc3a3 100644
- --- a/drivers/base/soc.c
- +++ b/drivers/base/soc.c
- @@ -13,6 +13,7 @@
- #include <linux/spinlock.h>
- #include <linux/sys_soc.h>
- #include <linux/err.h>
- +#include <linux/glob.h>
-
- static DEFINE_IDA(soc_ida);
-
- @@ -168,3 +169,68 @@ static int __init soc_bus_register(void)
- return bus_register(&soc_bus_type);
- }
- 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 &&
- + !glob_match(match->machine, soc_dev->attr->machine))
- + return 0;
- +
- + if (match->family &&
- + !glob_match(match->family, soc_dev->attr->family))
- + return 0;
- +
- + if (match->revision &&
- + !glob_match(match->revision, soc_dev->attr->revision))
- + return 0;
- +
- + if (match->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);
- diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
- index 2739ccb69571..9f5eb06f9fd8 100644
- --- a/include/linux/sys_soc.h
- +++ b/include/linux/sys_soc.h
- @@ -13,6 +13,7 @@ struct soc_device_attribute {
- const char *family;
- const char *revision;
- const char *soc_id;
- + const void *data;
- };
-
- /**
- @@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev);
- */
- struct device *soc_device_to_device(struct soc_device *soc);
-
- +const struct soc_device_attribute *soc_device_match(
- + const struct soc_device_attribute *matches);
- #endif /* __SOC_BUS_H */
- --
- 2.11.1
|