xref: /linux/drivers/base/physical_location.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
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 
17 	if (!has_acpi_companion(dev))
18 		return false;
19 
20 	if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld))
21 		return false;
22 
23 	dev->physical_location =
24 		kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
25 	if (!dev->physical_location) {
26 		ACPI_FREE(pld);
27 		return false;
28 	}
29 
30 	dev->physical_location->panel = pld->panel;
31 	dev->physical_location->vertical_position = pld->vertical_position;
32 	dev->physical_location->horizontal_position = pld->horizontal_position;
33 	dev->physical_location->dock = pld->dock;
34 	dev->physical_location->lid = pld->lid;
35 
36 	ACPI_FREE(pld);
37 	return true;
38 }
39 
40 static ssize_t panel_show(struct device *dev, struct device_attribute *attr,
41 	char *buf)
42 {
43 	const char *panel;
44 
45 	switch (dev->physical_location->panel) {
46 	case DEVICE_PANEL_TOP:
47 		panel = "top";
48 		break;
49 	case DEVICE_PANEL_BOTTOM:
50 		panel = "bottom";
51 		break;
52 	case DEVICE_PANEL_LEFT:
53 		panel = "left";
54 		break;
55 	case DEVICE_PANEL_RIGHT:
56 		panel = "right";
57 		break;
58 	case DEVICE_PANEL_FRONT:
59 		panel = "front";
60 		break;
61 	case DEVICE_PANEL_BACK:
62 		panel = "back";
63 		break;
64 	default:
65 		panel = "unknown";
66 	}
67 	return sysfs_emit(buf, "%s\n", panel);
68 }
69 static DEVICE_ATTR_RO(panel);
70 
71 static ssize_t vertical_position_show(struct device *dev,
72 	struct device_attribute *attr, char *buf)
73 {
74 	const char *vertical_position;
75 
76 	switch (dev->physical_location->vertical_position) {
77 	case DEVICE_VERT_POS_UPPER:
78 		vertical_position = "upper";
79 		break;
80 	case DEVICE_VERT_POS_CENTER:
81 		vertical_position = "center";
82 		break;
83 	case DEVICE_VERT_POS_LOWER:
84 		vertical_position = "lower";
85 		break;
86 	default:
87 		vertical_position = "unknown";
88 	}
89 	return sysfs_emit(buf, "%s\n", vertical_position);
90 }
91 static DEVICE_ATTR_RO(vertical_position);
92 
93 static ssize_t horizontal_position_show(struct device *dev,
94 	struct device_attribute *attr, char *buf)
95 {
96 	const char *horizontal_position;
97 
98 	switch (dev->physical_location->horizontal_position) {
99 	case DEVICE_HORI_POS_LEFT:
100 		horizontal_position = "left";
101 		break;
102 	case DEVICE_HORI_POS_CENTER:
103 		horizontal_position = "center";
104 		break;
105 	case DEVICE_HORI_POS_RIGHT:
106 		horizontal_position = "right";
107 		break;
108 	default:
109 		horizontal_position = "unknown";
110 	}
111 	return sysfs_emit(buf, "%s\n", horizontal_position);
112 }
113 static DEVICE_ATTR_RO(horizontal_position);
114 
115 static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
116 	char *buf)
117 {
118 	return sysfs_emit(buf, "%s\n",
119 		dev->physical_location->dock ? "yes" : "no");
120 }
121 static DEVICE_ATTR_RO(dock);
122 
123 static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
124 	char *buf)
125 {
126 	return sysfs_emit(buf, "%s\n",
127 		dev->physical_location->lid ? "yes" : "no");
128 }
129 static DEVICE_ATTR_RO(lid);
130 
131 static struct attribute *dev_attr_physical_location[] = {
132 	&dev_attr_panel.attr,
133 	&dev_attr_vertical_position.attr,
134 	&dev_attr_horizontal_position.attr,
135 	&dev_attr_dock.attr,
136 	&dev_attr_lid.attr,
137 	NULL,
138 };
139 
140 const struct attribute_group dev_attr_physical_location_group = {
141 	.name = "physical_location",
142 	.attrs = dev_attr_physical_location,
143 };
144 
145