diff options
Diffstat (limited to 'drivers/platform/surface/aggregator')
-rw-r--r-- | drivers/platform/surface/aggregator/bus.c | 2 | ||||
-rw-r--r-- | drivers/platform/surface/aggregator/controller.c | 67 | ||||
-rw-r--r-- | drivers/platform/surface/aggregator/core.c | 82 |
3 files changed, 118 insertions, 33 deletions
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index af8d573aae93..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> @@ -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..27eadf22b292 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; @@ -2715,11 +2753,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 797d0645bd77..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> @@ -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. ----------------------------------------------------- */ @@ -621,16 +639,17 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) struct device *dev = &serdev->dev; struct acpi_device *ssh = ACPI_COMPANION(dev); struct ssam_controller *ctrl; - acpi_status astatus; int status; - status = gpiod_count(dev, NULL); - if (status < 0) - return dev_err_probe(dev, status, "no GPIO found\n"); + 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(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); @@ -655,9 +674,9 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) goto err_devopen; } - astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev); - if (ACPI_FAILURE(astatus)) { - status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n"); + status = ssam_serdev_setup(ssh, serdev); + if (status) { + status = dev_err_probe(dev, status, "failed to setup serdev\n"); goto err_devinit; } @@ -717,7 +736,23 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) * For now let's thus default power/wakeup to false. */ device_set_wakeup_capable(dev, true); - acpi_dev_clear_dependencies(ssh); + + /* + * 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; @@ -782,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, |