diff options
author | Heikki Krogerus <heikki.krogerus@linux.intel.com> | 2017-06-16 11:21:25 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-27 17:55:45 +0200 |
commit | 8243edf44152c08c3efa1d551fc48605d674ad18 (patch) | |
tree | 3dd7b9ed384b537706b94ffda00cd87ed2826fa4 /drivers/usb/typec | |
parent | c1b0bc2dabfa884dea49c02adaf3cd6b52b33d2f (diff) | |
download | linux-8243edf44152c08c3efa1d551fc48605d674ad18.tar.bz2 |
usb: typec: ucsi: Add ACPI driver
Driver for ACPI UCSI interface method. This driver replaces
the previous UCSI driver drivers/usb/misc/ucsi.c.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r-- | drivers/usb/typec/ucsi/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi_acpi.c | 158 |
3 files changed, 176 insertions, 0 deletions
diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index da4c5c3d8870..d0c31cee4720 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -21,3 +21,19 @@ config TYPEC_UCSI To compile the driver as a module, choose M here: the module will be called typec_ucsi. + +if TYPEC_UCSI + +config UCSI_ACPI + tristate "UCSI ACPI Interface Driver" + depends on ACPI + help + This driver enables UCSI support on platforms that expose UCSI + interface as ACPI device. On new Intel Atom based platforms starting + from Broxton SoCs and Core platforms stating from Skylake, UCSI is an + ACPI enumerated device. + + To compile the driver as a module, choose M here: the module will be + called ucsi_acpi + +endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 87dd6ee6c9f3..8372fc22f9b3 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_TYPEC_UCSI) += typec_ucsi.o typec_ucsi-y := ucsi.o typec_ucsi-$(CONFIG_FTRACE) += trace.o + +obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c new file mode 100644 index 000000000000..3fb2e48e1c91 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -0,0 +1,158 @@ +/* + * UCSI ACPI driver + * + * Copyright (C) 2017, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/acpi.h> + +#include "ucsi.h" + +#define UCSI_DSM_UUID "6f8398c2-7ca4-11e4-ad36-631042b5008f" +#define UCSI_DSM_FUNC_WRITE 1 +#define UCSI_DSM_FUNC_READ 2 + +struct ucsi_acpi { + struct device *dev; + struct ucsi *ucsi; + struct ucsi_ppm ppm; + uuid_le uuid; +}; + +static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) +{ + union acpi_object *obj; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(ua->dev), ua->uuid.b, 1, func, + NULL); + if (!obj) { + dev_err(ua->dev, "%s: failed to evaluate _DSM %d\n", + __func__, func); + return -EIO; + } + + ACPI_FREE(obj); + return 0; +} + +static int ucsi_acpi_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl) +{ + struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); + + ppm->data->ctrl.raw_cmd = ctrl->raw_cmd; + + return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); +} + +static int ucsi_acpi_sync(struct ucsi_ppm *ppm) +{ + struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); + + return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); +} + +static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + struct ucsi_acpi *ua = data; + + ucsi_notify(ua->ucsi); +} + +static int ucsi_acpi_probe(struct platform_device *pdev) +{ + struct ucsi_acpi *ua; + struct resource *res; + acpi_status status; + int ret; + + ua = devm_kzalloc(&pdev->dev, sizeof(*ua), GFP_KERNEL); + if (!ua) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + /* + * NOTE: The memory region for the data structures is used also in an + * operation region, which means ACPI has already reserved it. Therefore + * it can not be requested here, and we can not use + * devm_ioremap_resource(). + */ + ua->ppm.data = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!ua->ppm.data) + return -ENOMEM; + + if (!ua->ppm.data->version) + return -ENODEV; + + ret = uuid_le_to_bin(UCSI_DSM_UUID, &ua->uuid); + if (ret) + return ret; + + ua->ppm.cmd = ucsi_acpi_cmd; + ua->ppm.sync = ucsi_acpi_sync; + ua->dev = &pdev->dev; + + status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_DEVICE_NOTIFY, + ucsi_acpi_notify, ua); + if (ACPI_FAILURE(status)) { + dev_err(&pdev->dev, "failed to install notify handler\n"); + return -ENODEV; + } + + ua->ucsi = ucsi_register_ppm(&pdev->dev, &ua->ppm); + if (IS_ERR(ua->ucsi)) { + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_DEVICE_NOTIFY, + ucsi_acpi_notify); + return PTR_ERR(ua->ucsi); + } + + platform_set_drvdata(pdev, ua); + + return 0; +} + +static int ucsi_acpi_remove(struct platform_device *pdev) +{ + struct ucsi_acpi *ua = platform_get_drvdata(pdev); + + ucsi_unregister_ppm(ua->ucsi); + + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, + ucsi_acpi_notify); + + return 0; +} + +static const struct acpi_device_id ucsi_acpi_match[] = { + { "PNP0CA0", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match); + +static struct platform_driver ucsi_acpi_platform_driver = { + .driver = { + .name = "ucsi_acpi", + .acpi_match_table = ACPI_PTR(ucsi_acpi_match), + }, + .probe = ucsi_acpi_probe, + .remove = ucsi_acpi_remove, +}; + +module_platform_driver(ucsi_acpi_platform_driver); + +MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("UCSI ACPI driver"); |