162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Device physical location support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Won Chung <wonchung@google.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/acpi.h>
962306a36Sopenharmony_ci#include <linux/sysfs.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "physical_location.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cibool dev_add_physical_location(struct device *dev)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct acpi_pld_info *pld;
1662306a36Sopenharmony_ci	acpi_status status;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	if (!has_acpi_companion(dev))
1962306a36Sopenharmony_ci		return false;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld);
2262306a36Sopenharmony_ci	if (ACPI_FAILURE(status))
2362306a36Sopenharmony_ci		return false;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	dev->physical_location =
2662306a36Sopenharmony_ci		kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
2762306a36Sopenharmony_ci	if (!dev->physical_location) {
2862306a36Sopenharmony_ci		ACPI_FREE(pld);
2962306a36Sopenharmony_ci		return false;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	dev->physical_location->panel = pld->panel;
3362306a36Sopenharmony_ci	dev->physical_location->vertical_position = pld->vertical_position;
3462306a36Sopenharmony_ci	dev->physical_location->horizontal_position = pld->horizontal_position;
3562306a36Sopenharmony_ci	dev->physical_location->dock = pld->dock;
3662306a36Sopenharmony_ci	dev->physical_location->lid = pld->lid;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	ACPI_FREE(pld);
3962306a36Sopenharmony_ci	return true;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic ssize_t panel_show(struct device *dev, struct device_attribute *attr,
4362306a36Sopenharmony_ci	char *buf)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	const char *panel;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	switch (dev->physical_location->panel) {
4862306a36Sopenharmony_ci	case DEVICE_PANEL_TOP:
4962306a36Sopenharmony_ci		panel = "top";
5062306a36Sopenharmony_ci		break;
5162306a36Sopenharmony_ci	case DEVICE_PANEL_BOTTOM:
5262306a36Sopenharmony_ci		panel = "bottom";
5362306a36Sopenharmony_ci		break;
5462306a36Sopenharmony_ci	case DEVICE_PANEL_LEFT:
5562306a36Sopenharmony_ci		panel = "left";
5662306a36Sopenharmony_ci		break;
5762306a36Sopenharmony_ci	case DEVICE_PANEL_RIGHT:
5862306a36Sopenharmony_ci		panel = "right";
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case DEVICE_PANEL_FRONT:
6162306a36Sopenharmony_ci		panel = "front";
6262306a36Sopenharmony_ci		break;
6362306a36Sopenharmony_ci	case DEVICE_PANEL_BACK:
6462306a36Sopenharmony_ci		panel = "back";
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	default:
6762306a36Sopenharmony_ci		panel = "unknown";
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", panel);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(panel);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic ssize_t vertical_position_show(struct device *dev,
7462306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	const char *vertical_position;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	switch (dev->physical_location->vertical_position) {
7962306a36Sopenharmony_ci	case DEVICE_VERT_POS_UPPER:
8062306a36Sopenharmony_ci		vertical_position = "upper";
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	case DEVICE_VERT_POS_CENTER:
8362306a36Sopenharmony_ci		vertical_position = "center";
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	case DEVICE_VERT_POS_LOWER:
8662306a36Sopenharmony_ci		vertical_position = "lower";
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	default:
8962306a36Sopenharmony_ci		vertical_position = "unknown";
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", vertical_position);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(vertical_position);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic ssize_t horizontal_position_show(struct device *dev,
9662306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	const char *horizontal_position;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	switch (dev->physical_location->horizontal_position) {
10162306a36Sopenharmony_ci	case DEVICE_HORI_POS_LEFT:
10262306a36Sopenharmony_ci		horizontal_position = "left";
10362306a36Sopenharmony_ci		break;
10462306a36Sopenharmony_ci	case DEVICE_HORI_POS_CENTER:
10562306a36Sopenharmony_ci		horizontal_position = "center";
10662306a36Sopenharmony_ci		break;
10762306a36Sopenharmony_ci	case DEVICE_HORI_POS_RIGHT:
10862306a36Sopenharmony_ci		horizontal_position = "right";
10962306a36Sopenharmony_ci		break;
11062306a36Sopenharmony_ci	default:
11162306a36Sopenharmony_ci		horizontal_position = "unknown";
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", horizontal_position);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(horizontal_position);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic ssize_t dock_show(struct device *dev, struct device_attribute *attr,
11862306a36Sopenharmony_ci	char *buf)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n",
12162306a36Sopenharmony_ci		dev->physical_location->dock ? "yes" : "no");
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dock);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic ssize_t lid_show(struct device *dev, struct device_attribute *attr,
12662306a36Sopenharmony_ci	char *buf)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n",
12962306a36Sopenharmony_ci		dev->physical_location->lid ? "yes" : "no");
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(lid);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic struct attribute *dev_attr_physical_location[] = {
13462306a36Sopenharmony_ci	&dev_attr_panel.attr,
13562306a36Sopenharmony_ci	&dev_attr_vertical_position.attr,
13662306a36Sopenharmony_ci	&dev_attr_horizontal_position.attr,
13762306a36Sopenharmony_ci	&dev_attr_dock.attr,
13862306a36Sopenharmony_ci	&dev_attr_lid.attr,
13962306a36Sopenharmony_ci	NULL,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ciconst struct attribute_group dev_attr_physical_location_group = {
14362306a36Sopenharmony_ci	.name = "physical_location",
14462306a36Sopenharmony_ci	.attrs = dev_attr_physical_location,
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
147