aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/soc.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2016-09-21 02:57:19 -0400
committerGeert Uytterhoeven <geert+renesas@glider.be>2016-11-10 04:10:29 -0500
commitc97db7cc7778e34a53b42d58c766f0ec0e30d580 (patch)
tree01cd10620028f0261ef411bbfec435ab6a64bef8 /drivers/base/soc.c
parent1da1b3628df34a2a5e38b70c8551770aadce969d (diff)
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 <arnd@arndb.de> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/soc.c')
-rw-r--r--drivers/base/soc.c66
1 files changed, 66 insertions, 0 deletions
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 @@
13#include <linux/spinlock.h> 13#include <linux/spinlock.h>
14#include <linux/sys_soc.h> 14#include <linux/sys_soc.h>
15#include <linux/err.h> 15#include <linux/err.h>
16#include <linux/glob.h>
16 17
17static DEFINE_IDA(soc_ida); 18static DEFINE_IDA(soc_ida);
18 19
@@ -168,3 +169,68 @@ static int __init soc_bus_register(void)
168 return bus_register(&soc_bus_type); 169 return bus_register(&soc_bus_type);
169} 170}
170core_initcall(soc_bus_register); 171core_initcall(soc_bus_register);
172
173static int soc_device_match_one(struct device *dev, void *arg)
174{
175 struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
176 const struct soc_device_attribute *match = arg;
177
178 if (match->machine &&
179 !glob_match(match->machine, soc_dev->attr->machine))
180 return 0;
181
182 if (match->family &&
183 !glob_match(match->family, soc_dev->attr->family))
184 return 0;
185
186 if (match->revision &&
187 !glob_match(match->revision, soc_dev->attr->revision))
188 return 0;
189
190 if (match->soc_id &&
191 !glob_match(match->soc_id, soc_dev->attr->soc_id))
192 return 0;
193
194 return 1;
195}
196
197/*
198 * soc_device_match - identify the SoC in the machine
199 * @matches: zero-terminated array of possible matches
200 *
201 * returns the first matching entry of the argument array, or NULL
202 * if none of them match.
203 *
204 * This function is meant as a helper in place of of_match_node()
205 * in cases where either no device tree is available or the information
206 * in a device node is insufficient to identify a particular variant
207 * by its compatible strings or other properties. For new devices,
208 * the DT binding should always provide unique compatible strings
209 * that allow the use of of_match_node() instead.
210 *
211 * The calling function can use the .data entry of the
212 * soc_device_attribute to pass a structure or function pointer for
213 * each entry.
214 */
215const struct soc_device_attribute *soc_device_match(
216 const struct soc_device_attribute *matches)
217{
218 int ret = 0;
219
220 if (!matches)
221 return NULL;
222
223 while (!ret) {
224 if (!(matches->machine || matches->family ||
225 matches->revision || matches->soc_id))
226 break;
227 ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
228 soc_device_match_one);
229 if (!ret)
230 matches++;
231 else
232 return matches;
233 }
234 return NULL;
235}
236EXPORT_SYMBOL_GPL(soc_device_match);