summaryrefslogtreecommitdiff
path: root/drivers/platform/surface
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/surface')
-rw-r--r--drivers/platform/surface/aggregator/bus.c6
-rw-r--r--drivers/platform/surface/aggregator/controller.c70
-rw-r--r--drivers/platform/surface/aggregator/core.c118
-rw-r--r--drivers/platform/surface/aggregator/ssh_msgb.h2
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.c2
-rw-r--r--drivers/platform/surface/aggregator/ssh_parser.c2
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.c2
-rw-r--r--drivers/platform/surface/aggregator/trace.h2
-rw-r--r--drivers/platform/surface/surface3-wmi.c2
-rw-r--r--drivers/platform/surface/surface3_power.c2
-rw-r--r--drivers/platform/surface/surface_acpi_notify.c4
-rw-r--r--drivers/platform/surface/surface_aggregator_cdev.c3
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c173
-rw-r--r--drivers/platform/surface/surface_aggregator_tabletsw.c2
-rw-r--r--drivers/platform/surface/surface_dtx.c3
-rw-r--r--drivers/platform/surface/surface_gpe.c2
-rw-r--r--drivers/platform/surface/surface_hotplug.c2
-rw-r--r--drivers/platform/surface/surface_platform_profile.c128
18 files changed, 410 insertions, 115 deletions
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index 118caa651bec..d68d231e716e 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -6,6 +6,7 @@
*/
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -306,9 +307,9 @@ const void *ssam_device_get_match_data(const struct ssam_device *dev)
}
EXPORT_SYMBOL_GPL(ssam_device_get_match_data);
-static int ssam_bus_match(struct device *dev, struct device_driver *drv)
+static int ssam_bus_match(struct device *dev, const struct device_driver *drv)
{
- struct ssam_device_driver *sdrv = to_ssam_device_driver(drv);
+ const struct ssam_device_driver *sdrv = to_ssam_device_driver(drv);
struct ssam_device *sdev = to_ssam_device(dev);
if (!is_ssam_device(dev))
@@ -441,6 +442,7 @@ static int ssam_add_client_device(struct device *parent, struct ssam_controller
sdev->dev.parent = parent;
sdev->dev.fwnode = fwnode_handle_get(node);
+ sdev->dev.of_node = to_of_node(node);
status = ssam_device_add(sdev);
if (status)
diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
index 7fc602e01487..a265e667538c 100644
--- a/drivers/platform/surface/aggregator/controller.c
+++ b/drivers/platform/surface/aggregator/controller.c
@@ -1104,13 +1104,6 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
u64 funcs;
int status;
- /* Set defaults. */
- caps->ssh_power_profile = U32_MAX;
- caps->screen_on_sleep_idle_timeout = U32_MAX;
- caps->screen_off_sleep_idle_timeout = U32_MAX;
- caps->d3_closes_handle = false;
- caps->ssh_buffer_size = U32_MAX;
-
/* Pre-load supported DSM functions. */
status = ssam_dsm_get_functions(handle, &funcs);
if (status)
@@ -1150,6 +1143,52 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
}
/**
+ * ssam_controller_caps_load_from_of() - Load controller capabilities from OF/DT.
+ * @dev: A pointer to the controller device
+ * @caps: Where to store the capabilities in.
+ *
+ * Return: Returns zero on success, a negative error code on failure.
+ */
+static int ssam_controller_caps_load_from_of(struct device *dev, struct ssam_controller_caps *caps)
+{
+ /*
+ * Every device starting with Surface Pro X through Laptop 7 uses these
+ * identical values, which makes them good defaults.
+ */
+ caps->d3_closes_handle = true;
+ caps->screen_on_sleep_idle_timeout = 5000;
+ caps->screen_off_sleep_idle_timeout = 30;
+ caps->ssh_buffer_size = 48;
+ /* TODO: figure out power profile */
+
+ return 0;
+}
+
+/**
+ * ssam_controller_caps_load() - Load controller capabilities
+ * @dev: A pointer to the controller device
+ * @caps: Where to store the capabilities in.
+ *
+ * Return: Returns zero on success, a negative error code on failure.
+ */
+static int ssam_controller_caps_load(struct device *dev, struct ssam_controller_caps *caps)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+
+ /* Set defaults. */
+ caps->ssh_power_profile = U32_MAX;
+ caps->screen_on_sleep_idle_timeout = U32_MAX;
+ caps->screen_off_sleep_idle_timeout = U32_MAX;
+ caps->d3_closes_handle = false;
+ caps->ssh_buffer_size = U32_MAX;
+
+ if (handle)
+ return ssam_controller_caps_load_from_acpi(handle, caps);
+ else
+ return ssam_controller_caps_load_from_of(dev, caps);
+}
+
+/**
* ssam_controller_init() - Initialize SSAM controller.
* @ctrl: The controller to initialize.
* @serdev: The serial device representing the underlying data transport.
@@ -1165,13 +1204,12 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
int ssam_controller_init(struct ssam_controller *ctrl,
struct serdev_device *serdev)
{
- acpi_handle handle = ACPI_HANDLE(&serdev->dev);
int status;
init_rwsem(&ctrl->lock);
kref_init(&ctrl->kref);
- status = ssam_controller_caps_load_from_acpi(handle, &ctrl->caps);
+ status = ssam_controller_caps_load(&serdev->dev, &ctrl->caps);
if (status)
return status;
@@ -1354,7 +1392,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl)
if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED)
return;
- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED);
+ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED &&
+ ctrl->state != SSAM_CONTROLLER_INITIALIZED);
/*
* Note: New events could still have been received after the previous
@@ -2715,11 +2754,12 @@ int ssam_irq_setup(struct ssam_controller *ctrl)
const int irqf = IRQF_ONESHOT | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN;
gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
- if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
-
- irq = gpiod_to_irq(gpiod);
- gpiod_put(gpiod);
+ if (IS_ERR(gpiod)) {
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ } else {
+ irq = gpiod_to_irq(gpiod);
+ gpiod_put(gpiod);
+ }
if (irq < 0)
return irq;
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index 9591a28bc38a..c58e1fdd1a5f 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -17,9 +17,12 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/serdev.h>
#include <linux/sysfs.h>
+#include <linux/units.h>
#include <linux/surface_aggregator/controller.h>
#include <linux/surface_aggregator/device.h>
@@ -227,8 +230,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind);
/* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
-static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
- size_t n)
+static size_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
+ size_t n)
{
struct ssam_controller *ctrl;
int ret;
@@ -299,7 +302,7 @@ static const struct attribute_group ssam_sam_group = {
};
-/* -- ACPI based device setup. ---------------------------------------------- */
+/* -- Serial device setup. -------------------------------------------------- */
static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
void *ctx)
@@ -352,13 +355,28 @@ static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
return AE_CTRL_TERMINATE;
}
-static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
- struct serdev_device *serdev)
+static int ssam_serdev_setup_via_acpi(struct serdev_device *serdev, acpi_handle handle)
{
- return acpi_walk_resources(handle, METHOD_NAME__CRS,
- ssam_serdev_setup_via_acpi_crs, serdev);
+ acpi_status status;
+
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ ssam_serdev_setup_via_acpi_crs, serdev);
+
+ return status ? -ENXIO : 0;
}
+static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serdev)
+{
+ if (ssh)
+ return ssam_serdev_setup_via_acpi(serdev, ssh->handle);
+
+ /* TODO: these values may differ per board/implementation */
+ serdev_device_set_baudrate(serdev, 4 * HZ_PER_MHZ);
+ serdev_device_set_flow_control(serdev, true);
+ serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+
+ return 0;
+}
/* -- Power management. ----------------------------------------------------- */
@@ -618,17 +636,20 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
static int ssam_serial_hub_probe(struct serdev_device *serdev)
{
- struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev);
+ struct device *dev = &serdev->dev;
+ struct acpi_device *ssh = ACPI_COMPANION(dev);
struct ssam_controller *ctrl;
- acpi_status astatus;
int status;
- if (gpiod_count(&serdev->dev, NULL) < 0)
- return -ENODEV;
+ if (ssh) {
+ status = gpiod_count(dev, NULL);
+ if (status < 0)
+ return dev_err_probe(dev, status, "no GPIO found\n");
- status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
- if (status)
- return status;
+ status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
+ if (status)
+ return status;
+ }
/* Allocate controller. */
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
@@ -637,8 +658,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
/* Initialize controller. */
status = ssam_controller_init(ctrl, serdev);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "failed to initialize ssam controller\n");
goto err_ctrl_init;
+ }
ssam_controller_lock(ctrl);
@@ -646,12 +669,14 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
serdev_device_set_drvdata(serdev, ctrl);
serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
status = serdev_device_open(serdev);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "failed to open serdev device\n");
goto err_devopen;
+ }
- astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
- if (ACPI_FAILURE(astatus)) {
- status = -ENXIO;
+ status = ssam_serdev_setup(ssh, serdev);
+ if (status) {
+ status = dev_err_probe(dev, status, "failed to setup serdev\n");
goto err_devinit;
}
@@ -667,25 +692,33 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
* states.
*/
status = ssam_log_firmware_version(ctrl);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "failed to get firmware version\n");
goto err_initrq;
+ }
status = ssam_ctrl_notif_d0_entry(ctrl);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "D0-entry notification failed\n");
goto err_initrq;
+ }
status = ssam_ctrl_notif_display_on(ctrl);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "display-on notification failed\n");
goto err_initrq;
+ }
- status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
+ status = sysfs_create_group(&dev->kobj, &ssam_sam_group);
if (status)
goto err_initrq;
/* Set up IRQ. */
status = ssam_irq_setup(ctrl);
- if (status)
+ if (status) {
+ dev_err_probe(dev, status, "failed to setup IRQ\n");
goto err_irq;
+ }
/* Finally, set main controller reference. */
status = ssam_try_set_controller(ctrl);
@@ -702,15 +735,31 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
* resumed. In short, this causes some spurious unwanted wake-ups.
* For now let's thus default power/wakeup to false.
*/
- device_set_wakeup_capable(&serdev->dev, true);
- acpi_dev_clear_dependencies(ssh);
+ device_set_wakeup_capable(dev, true);
+
+ /*
+ * When using DT, we have to register the platform hub driver manually,
+ * as it can't be matched based on top-level board compatible (like it
+ * does the ACPI case).
+ */
+ if (!ssh) {
+ struct platform_device *ph_pdev =
+ platform_device_register_simple("surface_aggregator_platform_hub",
+ 0, NULL, 0);
+ if (IS_ERR(ph_pdev))
+ return dev_err_probe(dev, PTR_ERR(ph_pdev),
+ "Failed to register the platform hub driver\n");
+ }
+
+ if (ssh)
+ acpi_dev_clear_dependencies(ssh);
return 0;
err_mainref:
ssam_irq_free(ctrl);
err_irq:
- sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
+ sysfs_remove_group(&dev->kobj, &ssam_sam_group);
err_initrq:
ssam_controller_lock(ctrl);
ssam_controller_shutdown(ctrl);
@@ -768,18 +817,27 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
device_set_wakeup_capable(&serdev->dev, false);
}
-static const struct acpi_device_id ssam_serial_hub_match[] = {
+static const struct acpi_device_id ssam_serial_hub_acpi_match[] = {
{ "MSHW0084", 0 },
{ },
};
-MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
+MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_acpi_match);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssam_serial_hub_of_match[] = {
+ { .compatible = "microsoft,surface-sam", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match);
+#endif
static struct serdev_device_driver ssam_serial_hub = {
.probe = ssam_serial_hub_probe,
.remove = ssam_serial_hub_remove,
.driver = {
.name = "surface_serial_hub",
- .acpi_match_table = ssam_serial_hub_match,
+ .acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match),
+ .of_match_table = of_match_ptr(ssam_serial_hub_of_match),
.pm = &ssam_serial_hub_pm_ops,
.shutdown = ssam_serial_hub_shutdown,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
index 438873e06098..80aa568a0759 100644
--- a/drivers/platform/surface/aggregator/ssh_msgb.h
+++ b/drivers/platform/surface/aggregator/ssh_msgb.h
@@ -8,7 +8,7 @@
#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
#define _SURFACE_AGGREGATOR_SSH_MSGB_H
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/types.h>
#include <linux/surface_aggregator/controller.h>
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index d726b1a86319..6081b0146d5f 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -5,7 +5,7 @@
* Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/atomic.h>
#include <linux/error-injection.h>
#include <linux/jiffies.h>
diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c
index a6f668694365..6cfda85d3b33 100644
--- a/drivers/platform/surface/aggregator/ssh_parser.c
+++ b/drivers/platform/surface/aggregator/ssh_parser.c
@@ -5,7 +5,7 @@
* Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/compiler.h>
#include <linux/device.h>
#include <linux/types.h>
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
index 90634dcacabf..879ca9ee7ff6 100644
--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
@@ -5,7 +5,7 @@
* Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/error-injection.h>
diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
index 55cc61bba1da..caf7d3cb5d8b 100644
--- a/drivers/platform/surface/aggregator/trace.h
+++ b/drivers/platform/surface/aggregator/trace.h
@@ -13,7 +13,7 @@
#include <linux/surface_aggregator/serial_hub.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/tracepoint.h>
TRACE_DEFINE_ENUM(SSH_FRAME_TYPE_DATA_SEQ);
diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c
index c15ed7a12784..6c8fb7a4dde4 100644
--- a/drivers/platform/surface/surface3-wmi.c
+++ b/drivers/platform/surface/surface3-wmi.c
@@ -247,7 +247,7 @@ static struct platform_driver s3_wmi_driver = {
.name = "surface3-wmi",
.pm = &s3_wmi_pm,
},
- .remove_new = s3_wmi_remove,
+ .remove = s3_wmi_remove,
};
static int __init s3_wmi_init(void)
diff --git a/drivers/platform/surface/surface3_power.c b/drivers/platform/surface/surface3_power.c
index 4c0f92562a79..1ee5239269ae 100644
--- a/drivers/platform/surface/surface3_power.c
+++ b/drivers/platform/surface/surface3_power.c
@@ -40,7 +40,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uuid.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SURFACE_3_POLL_INTERVAL (2 * HZ)
#define SURFACE_3_STRLEN 10
diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
index 20f3870915d2..3b30cfe3466b 100644
--- a/drivers/platform/surface/surface_acpi_notify.c
+++ b/drivers/platform/surface/surface_acpi_notify.c
@@ -11,7 +11,7 @@
* Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
@@ -850,7 +850,7 @@ MODULE_DEVICE_TABLE(acpi, san_match);
static struct platform_driver surface_acpi_notify = {
.probe = san_probe,
- .remove_new = san_remove,
+ .remove = san_remove,
.driver = {
.name = "surface_acpi_notify",
.acpi_match_table = san_match,
diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
index 07e065b9159f..bfaa09d1648b 100644
--- a/drivers/platform/surface/surface_aggregator_cdev.c
+++ b/drivers/platform/surface/surface_aggregator_cdev.c
@@ -670,7 +670,6 @@ static const struct file_operations ssam_controller_fops = {
.fasync = ssam_cdev_fasync,
.unlocked_ioctl = ssam_cdev_device_ioctl,
.compat_ioctl = ssam_cdev_device_ioctl,
- .llseek = no_llseek,
};
@@ -763,7 +762,7 @@ static struct platform_device *ssam_cdev_device;
static struct platform_driver ssam_cdev_driver = {
.probe = ssam_dbg_device_probe,
- .remove_new = ssam_dbg_device_remove,
+ .remove = ssam_dbg_device_remove,
.driver = {
.name = SSAM_CDEV_DEVICE_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index aeb3feae40ff..a594d5fcfcfd 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
@@ -68,12 +69,38 @@ static const struct software_node ssam_node_bat_sb3base = {
.parent = &ssam_node_hub_base,
};
-/* Platform profile / performance-mode device. */
-static const struct software_node ssam_node_tmp_pprof = {
+/* Platform profile / performance-mode device without a fan. */
+static const struct software_node ssam_node_tmp_perf_profile = {
.name = "ssam:01:03:01:00:01",
.parent = &ssam_node_root,
};
+/* Platform profile / performance-mode device with a fan, such that
+ * the fan controller profile can also be switched.
+ */
+static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = {
+ PROPERTY_ENTRY_BOOL("has_fan"),
+ { }
+};
+
+static const struct software_node ssam_node_tmp_perf_profile_with_fan = {
+ .name = "ssam:01:03:01:00:01",
+ .parent = &ssam_node_root,
+ .properties = ssam_node_tmp_perf_profile_has_fan,
+};
+
+/* Thermal sensors. */
+static const struct software_node ssam_node_tmp_sensors = {
+ .name = "ssam:01:03:01:00:02",
+ .parent = &ssam_node_root,
+};
+
+/* Fan speed function. */
+static const struct software_node ssam_node_fan_speed = {
+ .name = "ssam:01:05:01:01:01",
+ .parent = &ssam_node_root,
+};
+
/* Tablet-mode switch via KIP subsystem. */
static const struct software_node ssam_node_kip_tablet_switch = {
.name = "ssam:01:0e:01:00:01",
@@ -202,7 +229,7 @@ static const struct software_node ssam_node_pos_tablet_switch = {
*/
static const struct software_node *ssam_node_group_gen5[] = {
&ssam_node_root,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
NULL,
};
@@ -213,7 +240,7 @@ static const struct software_node *ssam_node_group_sb3[] = {
&ssam_node_bat_ac,
&ssam_node_bat_main,
&ssam_node_bat_sb3base,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
&ssam_node_bas_dtx,
&ssam_node_hid_base_keyboard,
&ssam_node_hid_base_touchpad,
@@ -227,7 +254,7 @@ static const struct software_node *ssam_node_group_sl3[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
&ssam_node_hid_main_keyboard,
&ssam_node_hid_main_touchpad,
&ssam_node_hid_main_iid5,
@@ -239,20 +266,50 @@ static const struct software_node *ssam_node_group_sl5[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_tmp_sensors,
+ &ssam_node_fan_speed,
+ &ssam_node_hid_main_keyboard,
+ &ssam_node_hid_main_touchpad,
+ &ssam_node_hid_main_iid5,
+ &ssam_node_hid_sam_ucm_ucsi,
+ NULL,
+};
+
+/* Devices for Surface Laptop 6. */
+static const struct software_node *ssam_node_group_sl6[] = {
+ &ssam_node_root,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_tmp_sensors,
+ &ssam_node_fan_speed,
&ssam_node_hid_main_keyboard,
&ssam_node_hid_main_touchpad,
&ssam_node_hid_main_iid5,
+ &ssam_node_hid_sam_sensors,
&ssam_node_hid_sam_ucm_ucsi,
NULL,
};
-/* Devices for Surface Laptop Studio. */
-static const struct software_node *ssam_node_group_sls[] = {
+/* Devices for Surface Laptop 7. */
+static const struct software_node *ssam_node_group_sl7[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_fan_speed,
+ &ssam_node_hid_sam_keyboard,
+ /* TODO: evaluate thermal sensors devices when we get a driver for that */
+ NULL,
+};
+
+/* Devices for Surface Laptop Studio 1. */
+static const struct software_node *ssam_node_group_sls1[] = {
+ &ssam_node_root,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_perf_profile,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_sam_keyboard,
&ssam_node_hid_sam_penstash,
@@ -263,12 +320,28 @@ static const struct software_node *ssam_node_group_sls[] = {
NULL,
};
+/* Devices for Surface Laptop Studio 2. */
+static const struct software_node *ssam_node_group_sls2[] = {
+ &ssam_node_root,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_tmp_sensors,
+ &ssam_node_fan_speed,
+ &ssam_node_pos_tablet_switch,
+ &ssam_node_hid_sam_keyboard,
+ &ssam_node_hid_sam_penstash,
+ &ssam_node_hid_sam_sensors,
+ &ssam_node_hid_sam_ucm_ucsi,
+ NULL,
+};
+
/* Devices for Surface Laptop Go. */
static const struct software_node *ssam_node_group_slg1[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
NULL,
};
@@ -277,7 +350,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
NULL,
};
@@ -287,7 +360,7 @@ static const struct software_node *ssam_node_group_sp8[] = {
&ssam_node_hub_kip,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile,
&ssam_node_kip_tablet_switch,
&ssam_node_hid_kip_keyboard,
&ssam_node_hid_kip_penstash,
@@ -298,13 +371,15 @@ static const struct software_node *ssam_node_group_sp8[] = {
NULL,
};
-/* Devices for Surface Pro 9 */
+/* Devices for Surface Pro 9, 10 and 11 (Intel/x86) */
static const struct software_node *ssam_node_group_sp9[] = {
&ssam_node_root,
&ssam_node_hub_kip,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_tmp_sensors,
+ &ssam_node_fan_speed,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_kip_keyboard,
&ssam_node_hid_kip_penstash,
@@ -315,10 +390,25 @@ static const struct software_node *ssam_node_group_sp9[] = {
NULL,
};
+/* Devices for Surface Pro 9 5G (ARM/QCOM) */
+static const struct software_node *ssam_node_group_sp9_5g[] = {
+ &ssam_node_root,
+ &ssam_node_hub_kip,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_sensors,
+ &ssam_node_hid_kip_keyboard,
+ &ssam_node_hid_kip_penstash,
+ &ssam_node_hid_kip_touchpad,
+ &ssam_node_hid_kip_fwupd,
+ &ssam_node_hid_sam_sensors,
+ &ssam_node_kip_tablet_switch,
+ NULL,
+};
/* -- SSAM platform/meta-hub driver. ---------------------------------------- */
-static const struct acpi_device_id ssam_platform_hub_match[] = {
+static const struct acpi_device_id ssam_platform_hub_acpi_match[] = {
/* Surface Pro 4, 5, and 6 (OMBR < 0x10) */
{ "MSHW0081", (unsigned long)ssam_node_group_gen5 },
@@ -337,6 +427,12 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Pro 9 */
{ "MSHW0343", (unsigned long)ssam_node_group_sp9 },
+ /* Surface Pro 10 */
+ { "MSHW0510", (unsigned long)ssam_node_group_sp9 },
+
+ /* Surface Pro 11 */
+ { "MSHW0583", (unsigned long)ssam_node_group_sp9 },
+
/* Surface Book 2 */
{ "MSHW0107", (unsigned long)ssam_node_group_gen5 },
@@ -361,29 +457,61 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop 5 */
{ "MSHW0350", (unsigned long)ssam_node_group_sl5 },
+ /* Surface Laptop 6 */
+ { "MSHW0530", (unsigned long)ssam_node_group_sl6 },
+
/* Surface Laptop Go 1 */
{ "MSHW0118", (unsigned long)ssam_node_group_slg1 },
/* Surface Laptop Go 2 */
{ "MSHW0290", (unsigned long)ssam_node_group_slg1 },
- /* Surface Laptop Studio */
- { "MSHW0123", (unsigned long)ssam_node_group_sls },
+ /* Surface Laptop Go 3 */
+ { "MSHW0440", (unsigned long)ssam_node_group_slg1 },
+
+ /* Surface Laptop Studio 1 */
+ { "MSHW0123", (unsigned long)ssam_node_group_sls1 },
+
+ /* Surface Laptop Studio 2 */
+ { "MSHW0360", (unsigned long)ssam_node_group_sls2 },
{ },
};
-MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
+MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_acpi_match);
+
+static const struct of_device_id ssam_platform_hub_of_match[] __maybe_unused = {
+ /* Surface Pro 9 5G (ARM/QCOM) */
+ { .compatible = "microsoft,arcata", (void *)ssam_node_group_sp9_5g },
+ /* Surface Laptop 7 */
+ { .compatible = "microsoft,romulus13", (void *)ssam_node_group_sl7 },
+ { .compatible = "microsoft,romulus15", (void *)ssam_node_group_sl7 },
+ { },
+};
static int ssam_platform_hub_probe(struct platform_device *pdev)
{
const struct software_node **nodes;
+ const struct of_device_id *match;
+ struct device_node *fdt_root;
struct ssam_controller *ctrl;
struct fwnode_handle *root;
int status;
nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
- if (!nodes)
- return -ENODEV;
+ if (!nodes) {
+ fdt_root = of_find_node_by_path("/");
+ if (!fdt_root)
+ return -ENODEV;
+
+ match = of_match_node(ssam_platform_hub_of_match, fdt_root);
+ of_node_put(fdt_root);
+ if (!match)
+ return -ENODEV;
+
+ nodes = (const struct software_node **)match->data;
+ if (!nodes)
+ return -ENODEV;
+ }
/*
* As we're adding the SSAM client devices as children under this device
@@ -429,15 +557,16 @@ static void ssam_platform_hub_remove(struct platform_device *pdev)
static struct platform_driver ssam_platform_hub_driver = {
.probe = ssam_platform_hub_probe,
- .remove_new = ssam_platform_hub_remove,
+ .remove = ssam_platform_hub_remove,
.driver = {
.name = "surface_aggregator_platform_hub",
- .acpi_match_table = ssam_platform_hub_match,
+ .acpi_match_table = ssam_platform_hub_acpi_match,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_platform_driver(ssam_platform_hub_driver);
+MODULE_ALIAS("platform:surface_aggregator_platform_hub");
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c
index c0a1a5869246..ffa36ed92897 100644
--- a/drivers/platform/surface/surface_aggregator_tabletsw.c
+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c
@@ -5,7 +5,7 @@
* Copyright (C) 2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
index 2de843b7ea70..97ae010069e4 100644
--- a/drivers/platform/surface/surface_dtx.c
+++ b/drivers/platform/surface/surface_dtx.c
@@ -555,7 +555,6 @@ static const struct file_operations surface_dtx_fops = {
.fasync = surface_dtx_fasync,
.unlocked_ioctl = surface_dtx_ioctl,
.compat_ioctl = surface_dtx_ioctl,
- .llseek = no_llseek,
};
@@ -1181,7 +1180,7 @@ MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match);
static struct platform_driver surface_dtx_platform_driver = {
.probe = surface_dtx_platform_probe,
- .remove_new = surface_dtx_platform_remove,
+ .remove = surface_dtx_platform_remove,
.driver = {
.name = "surface_dtx_pltf",
.acpi_match_table = surface_dtx_acpi_match,
diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c
index 62fd4004db31..b359413903b1 100644
--- a/drivers/platform/surface/surface_gpe.c
+++ b/drivers/platform/surface/surface_gpe.c
@@ -278,7 +278,7 @@ static void surface_gpe_remove(struct platform_device *pdev)
static struct platform_driver surface_gpe_driver = {
.probe = surface_gpe_probe,
- .remove_new = surface_gpe_remove,
+ .remove = surface_gpe_remove,
.driver = {
.name = "surface_gpe",
.pm = &surface_gpe_pm,
diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c
index a404f26cfae8..c0d83ed5a208 100644
--- a/drivers/platform/surface/surface_hotplug.c
+++ b/drivers/platform/surface/surface_hotplug.c
@@ -259,7 +259,7 @@ MODULE_DEVICE_TABLE(acpi, surface_hotplug_acpi_match);
static struct platform_driver surface_hotplug_driver = {
.probe = surface_hotplug_probe,
- .remove_new = surface_hotplug_remove,
+ .remove = surface_hotplug_remove,
.driver = {
.name = "surface_hotplug",
.acpi_match_table = surface_hotplug_acpi_match,
diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c
index a5a3941b3f43..0e479e35e66e 100644
--- a/drivers/platform/surface/surface_platform_profile.c
+++ b/drivers/platform/surface/surface_platform_profile.c
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Surface Platform Profile / Performance Mode driver for Surface System
- * Aggregator Module (thermal subsystem).
+ * Aggregator Module (thermal and fan subsystem).
*
* Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_profile.h>
@@ -14,6 +14,7 @@
#include <linux/surface_aggregator/device.h>
+// Enum for the platform performance profile sent to the TMP module.
enum ssam_tmp_profile {
SSAM_TMP_PROFILE_NORMAL = 1,
SSAM_TMP_PROFILE_BATTERY_SAVER = 2,
@@ -21,15 +22,26 @@ enum ssam_tmp_profile {
SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4,
};
+// Enum for the fan profile sent to the FAN module. This fan profile is
+// only sent to the EC if the 'has_fan' property is set. The integers are
+// not a typo, they differ from the performance profile indices.
+enum ssam_fan_profile {
+ SSAM_FAN_PROFILE_NORMAL = 2,
+ SSAM_FAN_PROFILE_BATTERY_SAVER = 1,
+ SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3,
+ SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4,
+};
+
struct ssam_tmp_profile_info {
__le32 profile;
__le16 unknown1;
__le16 unknown2;
} __packed;
-struct ssam_tmp_profile_device {
+struct ssam_platform_profile_device {
struct ssam_device *sdev;
- struct platform_profile_handler handler;
+ struct device *ppdev;
+ bool has_fan;
};
SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, {
@@ -42,6 +54,13 @@ SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, {
.command_id = 0x03,
});
+SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, u8, {
+ .target_category = SSAM_SSH_TC_FAN,
+ .target_id = SSAM_SSH_TID_SAM,
+ .command_id = 0x0e,
+ .instance_id = 0x01,
+});
+
static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p)
{
struct ssam_tmp_profile_info info;
@@ -57,12 +76,19 @@ static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile
static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile p)
{
- __le32 profile_le = cpu_to_le32(p);
+ const __le32 profile_le = cpu_to_le32(p);
return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le);
}
-static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
+static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p)
+{
+ const u8 profile = p;
+
+ return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile);
+}
+
+static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
{
switch (p) {
case SSAM_TMP_PROFILE_NORMAL:
@@ -83,7 +109,8 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi
}
}
-static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p)
+
+static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p)
{
switch (p) {
case PLATFORM_PROFILE_LOW_POWER:
@@ -105,20 +132,42 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi
}
}
-static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
+static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p)
+{
+ switch (p) {
+ case PLATFORM_PROFILE_LOW_POWER:
+ return SSAM_FAN_PROFILE_BATTERY_SAVER;
+
+ case PLATFORM_PROFILE_BALANCED:
+ return SSAM_FAN_PROFILE_NORMAL;
+
+ case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
+ return SSAM_FAN_PROFILE_BETTER_PERFORMANCE;
+
+ case PLATFORM_PROFILE_PERFORMANCE:
+ return SSAM_FAN_PROFILE_BEST_PERFORMANCE;
+
+ default:
+ /* This should have already been caught by platform_profile_store(). */
+ WARN(true, "unsupported platform profile");
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ssam_platform_profile_get(struct device *dev,
enum platform_profile_option *profile)
{
- struct ssam_tmp_profile_device *tpd;
+ struct ssam_platform_profile_device *tpd;
enum ssam_tmp_profile tp;
int status;
- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
+ tpd = dev_get_drvdata(dev);
status = ssam_tmp_profile_get(tpd->sdev, &tp);
if (status)
return status;
- status = convert_ssam_to_profile(tpd->sdev, tp);
+ status = convert_ssam_tmp_to_profile(tpd->sdev, tp);
if (status < 0)
return status;
@@ -126,45 +175,65 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
return 0;
}
-static int ssam_platform_profile_set(struct platform_profile_handler *pprof,
+static int ssam_platform_profile_set(struct device *dev,
enum platform_profile_option profile)
{
- struct ssam_tmp_profile_device *tpd;
+ struct ssam_platform_profile_device *tpd;
int tp;
- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
+ tpd = dev_get_drvdata(dev);
- tp = convert_profile_to_ssam(tpd->sdev, profile);
+ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile);
if (tp < 0)
return tp;
- return ssam_tmp_profile_set(tpd->sdev, tp);
+ tp = ssam_tmp_profile_set(tpd->sdev, tp);
+ if (tp < 0)
+ return tp;
+
+ if (tpd->has_fan) {
+ tp = convert_profile_to_ssam_fan(tpd->sdev, profile);
+ if (tp < 0)
+ return tp;
+ tp = ssam_fan_profile_set(tpd->sdev, tp);
+ }
+
+ return tp;
}
+static int ssam_platform_profile_probe(void *drvdata, unsigned long *choices)
+{
+ set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
+ set_bit(PLATFORM_PROFILE_BALANCED, choices);
+ set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
+ set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
+
+ return 0;
+}
+
+static const struct platform_profile_ops ssam_platform_profile_ops = {
+ .probe = ssam_platform_profile_probe,
+ .profile_get = ssam_platform_profile_get,
+ .profile_set = ssam_platform_profile_set,
+};
+
static int surface_platform_profile_probe(struct ssam_device *sdev)
{
- struct ssam_tmp_profile_device *tpd;
+ struct ssam_platform_profile_device *tpd;
tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL);
if (!tpd)
return -ENOMEM;
tpd->sdev = sdev;
+ ssam_device_set_drvdata(sdev, tpd);
- tpd->handler.profile_get = ssam_platform_profile_get;
- tpd->handler.profile_set = ssam_platform_profile_set;
+ tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan");
- set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices);
- set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
- set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
- set_bit(PLATFORM_PROFILE_PERFORMANCE, tpd->handler.choices);
+ tpd->ppdev = devm_platform_profile_register(&sdev->dev, "Surface Platform Profile",
+ tpd, &ssam_platform_profile_ops);
- return platform_profile_register(&tpd->handler);
-}
-
-static void surface_platform_profile_remove(struct ssam_device *sdev)
-{
- platform_profile_remove();
+ return PTR_ERR_OR_ZERO(tpd->ppdev);
}
static const struct ssam_device_id ssam_platform_profile_match[] = {
@@ -175,7 +244,6 @@ MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match);
static struct ssam_device_driver surface_platform_profile = {
.probe = surface_platform_profile_probe,
- .remove = surface_platform_profile_remove,
.match_table = ssam_platform_profile_match,
.driver = {
.name = "surface_platform_profile",