@@ -2171,6 +2171,15 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
2171
2171
}
2172
2172
EXPORT_SYMBOL_GPL (of_genpd_remove_last );
2173
2173
2174
+ static void genpd_release_dev (struct device * dev )
2175
+ {
2176
+ kfree (dev );
2177
+ }
2178
+
2179
+ static struct bus_type genpd_bus_type = {
2180
+ .name = "genpd" ,
2181
+ };
2182
+
2174
2183
/**
2175
2184
* genpd_dev_pm_detach - Detach a device from its PM domain.
2176
2185
* @dev: Device to detach.
@@ -2208,6 +2217,10 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
2208
2217
2209
2218
/* Check if PM domain can be powered off after removing this device. */
2210
2219
genpd_queue_power_off_work (pd );
2220
+
2221
+ /* Unregister the device if it was created by genpd. */
2222
+ if (dev -> bus == & genpd_bus_type )
2223
+ device_unregister (dev );
2211
2224
}
2212
2225
2213
2226
static void genpd_dev_pm_sync (struct device * dev )
@@ -2221,32 +2234,17 @@ static void genpd_dev_pm_sync(struct device *dev)
2221
2234
genpd_queue_power_off_work (pd );
2222
2235
}
2223
2236
2224
- /**
2225
- * genpd_dev_pm_attach - Attach a device to its PM domain using DT.
2226
- * @dev: Device to attach.
2227
- *
2228
- * Parse device's OF node to find a PM domain specifier. If such is found,
2229
- * attaches the device to retrieved pm_domain ops.
2230
- *
2231
- * Returns 1 on successfully attached PM domain, 0 when the device don't need a
2232
- * PM domain or a negative error code in case of failures. Note that if a
2233
- * power-domain exists for the device, but it cannot be found or turned on,
2234
- * then return -EPROBE_DEFER to ensure that the device is not probed and to
2235
- * re-try again later.
2236
- */
2237
- int genpd_dev_pm_attach (struct device * dev )
2237
+ static int __genpd_dev_pm_attach (struct device * dev , struct device_node * np ,
2238
+ unsigned int index )
2238
2239
{
2239
2240
struct of_phandle_args pd_args ;
2240
2241
struct generic_pm_domain * pd ;
2241
2242
int ret ;
2242
2243
2243
- if (!dev -> of_node )
2244
- return 0 ;
2245
-
2246
- ret = of_parse_phandle_with_args (dev -> of_node , "power-domains" ,
2247
- "#power-domain-cells" , 0 , & pd_args );
2244
+ ret = of_parse_phandle_with_args (np , "power-domains" ,
2245
+ "#power-domain-cells" , index , & pd_args );
2248
2246
if (ret < 0 )
2249
- return 0 ;
2247
+ return ret ;
2250
2248
2251
2249
mutex_lock (& gpd_list_lock );
2252
2250
pd = genpd_get_from_provider (& pd_args );
@@ -2282,8 +2280,98 @@ int genpd_dev_pm_attach(struct device *dev)
2282
2280
2283
2281
return ret ? - EPROBE_DEFER : 1 ;
2284
2282
}
2283
+
2284
+ /**
2285
+ * genpd_dev_pm_attach - Attach a device to its PM domain using DT.
2286
+ * @dev: Device to attach.
2287
+ *
2288
+ * Parse device's OF node to find a PM domain specifier. If such is found,
2289
+ * attaches the device to retrieved pm_domain ops.
2290
+ *
2291
+ * Returns 1 on successfully attached PM domain, 0 when the device don't need a
2292
+ * PM domain or when multiple power-domains exists for it, else a negative error
2293
+ * code. Note that if a power-domain exists for the device, but it cannot be
2294
+ * found or turned on, then return -EPROBE_DEFER to ensure that the device is
2295
+ * not probed and to re-try again later.
2296
+ */
2297
+ int genpd_dev_pm_attach (struct device * dev )
2298
+ {
2299
+ if (!dev -> of_node )
2300
+ return 0 ;
2301
+
2302
+ /*
2303
+ * Devices with multiple PM domains must be attached separately, as we
2304
+ * can only attach one PM domain per device.
2305
+ */
2306
+ if (of_count_phandle_with_args (dev -> of_node , "power-domains" ,
2307
+ "#power-domain-cells" ) != 1 )
2308
+ return 0 ;
2309
+
2310
+ return __genpd_dev_pm_attach (dev , dev -> of_node , 0 );
2311
+ }
2285
2312
EXPORT_SYMBOL_GPL (genpd_dev_pm_attach );
2286
2313
2314
+ /**
2315
+ * genpd_dev_pm_attach_by_id - Associate a device with one of its PM domains.
2316
+ * @dev: The device used to lookup the PM domain.
2317
+ * @index: The index of the PM domain.
2318
+ *
2319
+ * Parse device's OF node to find a PM domain specifier at the provided @index.
2320
+ * If such is found, creates a virtual device and attaches it to the retrieved
2321
+ * pm_domain ops. To deal with detaching of the virtual device, the ->detach()
2322
+ * callback in the struct dev_pm_domain are assigned to genpd_dev_pm_detach().
2323
+ *
2324
+ * Returns the created virtual device if successfully attached PM domain, NULL
2325
+ * when the device don't need a PM domain, else an ERR_PTR() in case of
2326
+ * failures. If a power-domain exists for the device, but cannot be found or
2327
+ * turned on, then ERR_PTR(-EPROBE_DEFER) is returned to ensure that the device
2328
+ * is not probed and to re-try again later.
2329
+ */
2330
+ struct device * genpd_dev_pm_attach_by_id (struct device * dev ,
2331
+ unsigned int index )
2332
+ {
2333
+ struct device * genpd_dev ;
2334
+ int num_domains ;
2335
+ int ret ;
2336
+
2337
+ if (!dev -> of_node )
2338
+ return NULL ;
2339
+
2340
+ /* Deal only with devices using multiple PM domains. */
2341
+ num_domains = of_count_phandle_with_args (dev -> of_node , "power-domains" ,
2342
+ "#power-domain-cells" );
2343
+ if (num_domains < 2 || index >= num_domains )
2344
+ return NULL ;
2345
+
2346
+ /* Allocate and register device on the genpd bus. */
2347
+ genpd_dev = kzalloc (sizeof (* genpd_dev ), GFP_KERNEL );
2348
+ if (!genpd_dev )
2349
+ return ERR_PTR (- ENOMEM );
2350
+
2351
+ dev_set_name (genpd_dev , "genpd:%u:%s" , index , dev_name (dev ));
2352
+ genpd_dev -> bus = & genpd_bus_type ;
2353
+ genpd_dev -> release = genpd_release_dev ;
2354
+
2355
+ ret = device_register (genpd_dev );
2356
+ if (ret ) {
2357
+ kfree (genpd_dev );
2358
+ return ERR_PTR (ret );
2359
+ }
2360
+
2361
+ /* Try to attach the device to the PM domain at the specified index. */
2362
+ ret = __genpd_dev_pm_attach (genpd_dev , dev -> of_node , index );
2363
+ if (ret < 1 ) {
2364
+ device_unregister (genpd_dev );
2365
+ return ret ? ERR_PTR (ret ) : NULL ;
2366
+ }
2367
+
2368
+ pm_runtime_set_active (genpd_dev );
2369
+ pm_runtime_enable (genpd_dev );
2370
+
2371
+ return genpd_dev ;
2372
+ }
2373
+ EXPORT_SYMBOL_GPL (genpd_dev_pm_attach_by_id );
2374
+
2287
2375
static const struct of_device_id idle_state_match [] = {
2288
2376
{ .compatible = "domain-idle-state" , },
2289
2377
{ }
@@ -2443,6 +2531,12 @@ unsigned int of_genpd_opp_to_performance_state(struct device *dev,
2443
2531
}
2444
2532
EXPORT_SYMBOL_GPL (of_genpd_opp_to_performance_state );
2445
2533
2534
+ static int __init genpd_bus_init (void )
2535
+ {
2536
+ return bus_register (& genpd_bus_type );
2537
+ }
2538
+ core_initcall (genpd_bus_init );
2539
+
2446
2540
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
2447
2541
2448
2542
0 commit comments