aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/soc.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert+renesas@glider.be>2017-03-09 08:17:50 -0500
committerGeert Uytterhoeven <geert+renesas@glider.be>2017-03-29 15:43:26 -0400
commit6e12db376b60b7158e4e6006af60566f8c68f7ab (patch)
treef4b658d5c31dd927d27fafaf7bbcb0e7c2514fbb /drivers/base/soc.c
parent0656db9e445a12122f76e259ab89d256cb07a0ad (diff)
base: soc: Allow early registration of a single SoC device
Commit 1da1b3628df34a2a ("base: soc: Early register bus when needed") added support for early registration of SoC devices from a core_initcall(). However, some drivers need to check the SoC revision from an early_initcall(), which is even earlier. A specific example is the Renesas R-Car SYSC driver, which manages PM Domains and thus needs to be initialized from an early_initcall. Preproduction versions of the R-Car H3 SoC have an additional power area, which no longer exists on H3 ES2.0, so the R-Car SYSC driver needs to check the exact SoC revision before instantiating a PM Domain for that power area. While registering the SoC bus and device, and using soc_device_match(), from an early_initcall() do work, the "soc" directory and the "soc0" file end up wrongly in the sysfs root, as the "bus" resp. "devices" directories haven't been created yet. To fix this, allow to register a single SoC device early on. As long as the SoC bus isn't registered, soc_device_match() just matches against this early device. When the SoC bus is registered later, the early device is registered for real. Note that soc_device_register() returns NULL (no error, but also not a valid pointer) when registering an early device. Hence platform devices cannot be instantiated as children of the "soc0" node representing an early SoC device. This should not be an issue, as that practice has been deprecated for new platforms. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/base/soc.c')
-rw-r--r--drivers/base/soc.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 50033081834a..909dedae4c4e 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -109,15 +109,18 @@ static void soc_release(struct device *dev)
109 kfree(soc_dev); 109 kfree(soc_dev);
110} 110}
111 111
112static struct soc_device_attribute *early_soc_dev_attr;
113
112struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) 114struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
113{ 115{
114 struct soc_device *soc_dev; 116 struct soc_device *soc_dev;
115 int ret; 117 int ret;
116 118
117 if (!soc_bus_type.p) { 119 if (!soc_bus_type.p) {
118 ret = bus_register(&soc_bus_type); 120 if (early_soc_dev_attr)
119 if (ret) 121 return ERR_PTR(-EBUSY);
120 goto out1; 122 early_soc_dev_attr = soc_dev_attr;
123 return NULL;
121 } 124 }
122 125
123 soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL); 126 soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
@@ -159,45 +162,53 @@ void soc_device_unregister(struct soc_device *soc_dev)
159 ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); 162 ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
160 163
161 device_unregister(&soc_dev->dev); 164 device_unregister(&soc_dev->dev);
165 early_soc_dev_attr = NULL;
162} 166}
163 167
164static int __init soc_bus_register(void) 168static int __init soc_bus_register(void)
165{ 169{
166 if (soc_bus_type.p) 170 int ret;
167 return 0;
168 171
169 return bus_register(&soc_bus_type); 172 ret = bus_register(&soc_bus_type);
173 if (ret)
174 return ret;
175
176 if (early_soc_dev_attr)
177 return PTR_ERR(soc_device_register(early_soc_dev_attr));
178
179 return 0;
170} 180}
171core_initcall(soc_bus_register); 181core_initcall(soc_bus_register);
172 182
173static int soc_device_match_one(struct device *dev, void *arg) 183static int soc_device_match_attr(const struct soc_device_attribute *attr,
184 const struct soc_device_attribute *match)
174{ 185{
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 && 186 if (match->machine &&
179 (!soc_dev->attr->machine || 187 (!attr->machine || !glob_match(match->machine, attr->machine)))
180 !glob_match(match->machine, soc_dev->attr->machine)))
181 return 0; 188 return 0;
182 189
183 if (match->family && 190 if (match->family &&
184 (!soc_dev->attr->family || 191 (!attr->family || !glob_match(match->family, attr->family)))
185 !glob_match(match->family, soc_dev->attr->family)))
186 return 0; 192 return 0;
187 193
188 if (match->revision && 194 if (match->revision &&
189 (!soc_dev->attr->revision || 195 (!attr->revision || !glob_match(match->revision, attr->revision)))
190 !glob_match(match->revision, soc_dev->attr->revision)))
191 return 0; 196 return 0;
192 197
193 if (match->soc_id && 198 if (match->soc_id &&
194 (!soc_dev->attr->soc_id || 199 (!attr->soc_id || !glob_match(match->soc_id, attr->soc_id)))
195 !glob_match(match->soc_id, soc_dev->attr->soc_id)))
196 return 0; 200 return 0;
197 201
198 return 1; 202 return 1;
199} 203}
200 204
205static int soc_device_match_one(struct device *dev, void *arg)
206{
207 struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
208
209 return soc_device_match_attr(soc_dev->attr, arg);
210}
211
201/* 212/*
202 * soc_device_match - identify the SoC in the machine 213 * soc_device_match - identify the SoC in the machine
203 * @matches: zero-terminated array of possible matches 214 * @matches: zero-terminated array of possible matches
@@ -230,6 +241,9 @@ const struct soc_device_attribute *soc_device_match(
230 break; 241 break;
231 ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, 242 ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
232 soc_device_match_one); 243 soc_device_match_one);
244 if (ret < 0 && early_soc_dev_attr)
245 ret = soc_device_match_attr(early_soc_dev_attr,
246 matches);
233 if (ret < 0) 247 if (ret < 0)
234 return NULL; 248 return NULL;
235 if (!ret) 249 if (!ret)