GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / base / physical_location.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Device physical location support
4  *
5  * Author: Won Chung <wonchung@google.com>
6  */
7
8 #include <linux/acpi.h>
9 #include <linux/sysfs.h>
10
11 #include "physical_location.h"
12
13 bool dev_add_physical_location(struct device *dev)
14 {
15         struct acpi_pld_info *pld;
16         acpi_status status;
17
18         if (!has_acpi_companion(dev))
19                 return false;
20
21         status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld);
22         if (ACPI_FAILURE(status))
23                 return false;
24
25         dev->physical_location =
26                 kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
27         if (!dev->physical_location)
28                 return false;
29         dev->physical_location->panel = pld->panel;
30         dev->physical_location->vertical_position = pld->vertical_position;
31         dev->physical_location->horizontal_position = pld->horizontal_position;
32         dev->physical_location->dock = pld->dock;
33         dev->physical_location->lid = pld->lid;
34
35         ACPI_FREE(pld);
36         return true;
37 }
38
39 static ssize_t panel_show(struct device *dev, struct device_attribute *attr,
40         char *buf)
41 {
42         const char *panel;
43
44         switch (dev->physical_location->panel) {
45         case DEVICE_PANEL_TOP:
46                 panel = "top";
47                 break;
48         case DEVICE_PANEL_BOTTOM:
49                 panel = "bottom";
50                 break;
51         case DEVICE_PANEL_LEFT:
52                 panel = "left";
53                 break;
54         case DEVICE_PANEL_RIGHT:
55                 panel = "right";
56                 break;
57         case DEVICE_PANEL_FRONT:
58                 panel = "front";
59                 break;
60         case DEVICE_PANEL_BACK:
61                 panel = "back";
62                 break;
63         default:
64                 panel = "unknown";
65         }
66         return sysfs_emit(buf, "%s\n", panel);
67 }
68 static DEVICE_ATTR_RO(panel);
69
70 static ssize_t vertical_position_show(struct device *dev,
71         struct device_attribute *attr, char *buf)
72 {
73         const char *vertical_position;
74
75         switch (dev->physical_location->vertical_position) {
76         case DEVICE_VERT_POS_UPPER:
77                 vertical_position = "upper";
78                 break;
79         case DEVICE_VERT_POS_CENTER:
80                 vertical_position = "center";
81                 break;
82         case DEVICE_VERT_POS_LOWER:
83                 vertical_position = "lower";
84                 break;
85         default:
86                 vertical_position = "unknown";
87         }
88         return sysfs_emit(buf, "%s\n", vertical_position);
89 }
90 static DEVICE_ATTR_RO(vertical_position);
91
92 static ssize_t horizontal_position_show(struct device *dev,
93         struct device_attribute *attr, char *buf)
94 {
95         const char *horizontal_position;
96
97         switch (dev->physical_location->horizontal_position) {
98         case DEVICE_HORI_POS_LEFT:
99                 horizontal_position = "left";
100                 break;
101         case DEVICE_HORI_POS_CENTER:
102                 horizontal_position = "center";
103                 break;
104         case DEVICE_HORI_POS_RIGHT:
105                 horizontal_position = "right";
106                 break;
107         default:
108                 horizontal_position = "unknown";
109         }
110         return sysfs_emit(buf, "%s\n", horizontal_position);
111 }
112 static DEVICE_ATTR_RO(horizontal_position);
113
114 static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
115         char *buf)
116 {
117         return sysfs_emit(buf, "%s\n",
118                 dev->physical_location->dock ? "yes" : "no");
119 }
120 static DEVICE_ATTR_RO(dock);
121
122 static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
123         char *buf)
124 {
125         return sysfs_emit(buf, "%s\n",
126                 dev->physical_location->lid ? "yes" : "no");
127 }
128 static DEVICE_ATTR_RO(lid);
129
130 static struct attribute *dev_attr_physical_location[] = {
131         &dev_attr_panel.attr,
132         &dev_attr_vertical_position.attr,
133         &dev_attr_horizontal_position.attr,
134         &dev_attr_dock.attr,
135         &dev_attr_lid.attr,
136         NULL,
137 };
138
139 const struct attribute_group dev_attr_physical_location_group = {
140         .name = "physical_location",
141         .attrs = dev_attr_physical_location,
142 };
143