WIP: merge_config
[platform/kernel/linux-starfive.git] / drivers / acpi / container.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * container.c  - ACPI Generic Container Driver
4  *
5  * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
6  * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
7  * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
8  * Copyright (C) 2004 FUJITSU LIMITED
9  * Copyright (C) 2004, 2013 Intel Corp.
10  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
11  */
12 #include <linux/acpi.h>
13 #include <linux/container.h>
14
15 #include "internal.h"
16
17 static const struct acpi_device_id container_device_ids[] = {
18         {"ACPI0004", 0},
19         {"PNP0A05", 0},
20         {"PNP0A06", 0},
21         {"", 0},
22 };
23
24 #ifdef CONFIG_ACPI_CONTAINER
25
26 static int check_offline(struct acpi_device *adev, void *not_used)
27 {
28         if (acpi_scan_is_offline(adev, false))
29                 return 0;
30
31         return -EBUSY;
32 }
33
34 static int acpi_container_offline(struct container_dev *cdev)
35 {
36         /* Check all of the dependent devices' physical companions. */
37         return acpi_dev_for_each_child(ACPI_COMPANION(&cdev->dev), check_offline, NULL);
38 }
39
40 static void acpi_container_release(struct device *dev)
41 {
42         kfree(to_container_dev(dev));
43 }
44
45 static int container_device_attach(struct acpi_device *adev,
46                                    const struct acpi_device_id *not_used)
47 {
48         struct container_dev *cdev;
49         struct device *dev;
50         int ret;
51
52         if (adev->flags.is_dock_station)
53                 return 0;
54
55         cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
56         if (!cdev)
57                 return -ENOMEM;
58
59         cdev->offline = acpi_container_offline;
60         dev = &cdev->dev;
61         dev->bus = &container_subsys;
62         dev_set_name(dev, "%s", dev_name(&adev->dev));
63         ACPI_COMPANION_SET(dev, adev);
64         dev->release = acpi_container_release;
65         ret = device_register(dev);
66         if (ret) {
67                 put_device(dev);
68                 return ret;
69         }
70         adev->driver_data = dev;
71         return 1;
72 }
73
74 static void container_device_detach(struct acpi_device *adev)
75 {
76         struct device *dev = acpi_driver_data(adev);
77
78         adev->driver_data = NULL;
79         if (dev)
80                 device_unregister(dev);
81 }
82
83 static void container_device_online(struct acpi_device *adev)
84 {
85         struct device *dev = acpi_driver_data(adev);
86
87         kobject_uevent(&dev->kobj, KOBJ_ONLINE);
88 }
89
90 static struct acpi_scan_handler container_handler = {
91         .ids = container_device_ids,
92         .attach = container_device_attach,
93         .detach = container_device_detach,
94         .hotplug = {
95                 .enabled = true,
96                 .demand_offline = true,
97                 .notify_online = container_device_online,
98         },
99 };
100
101 void __init acpi_container_init(void)
102 {
103         acpi_scan_add_handler(&container_handler);
104 }
105
106 #else
107
108 static struct acpi_scan_handler container_handler = {
109         .ids = container_device_ids,
110 };
111
112 void __init acpi_container_init(void)
113 {
114         acpi_scan_add_handler_with_hotplug(&container_handler, "container");
115 }
116
117 #endif /* CONFIG_ACPI_CONTAINER */