// SPDX-License-Identifier: GPL-2.0
/*
 * UCSI ACPI driver
 *
 * Copyright (C) 2017, Intel Corporation
 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
 */

#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/dmi.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;
	void *base;
	struct completion complete;
	unsigned long flags;
	guid_t guid;
	u64 cmd;
	bool dell_quirk_probed;
	bool dell_quirk_active;
};

static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func)
{
	union acpi_object *obj;

	obj = acpi_evaluate_dsm(ACPI_HANDLE(ua->dev), &ua->guid, 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_read(struct ucsi *ucsi, unsigned int offset,
			  void *val, size_t val_len)
{
	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
	int ret;

	ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
	if (ret)
		return ret;

	memcpy(val, ua->base + offset, val_len);

	return 0;
}

static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset,
				 const void *val, size_t val_len)
{
	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);

	memcpy(ua->base + offset, val, val_len);
	ua->cmd = *(u64 *)val;

	return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
}

static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset,
				const void *val, size_t val_len)
{
	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
	bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
	int ret;

	if (ack)
		set_bit(ACK_PENDING, &ua->flags);
	else
		set_bit(COMMAND_PENDING, &ua->flags);

	ret = ucsi_acpi_async_write(ucsi, offset, val, val_len);
	if (ret)
		goto out_clear_bit;

	if (!wait_for_completion_timeout(&ua->complete, 5 * HZ))
		ret = -ETIMEDOUT;

out_clear_bit:
	if (ack)
		clear_bit(ACK_PENDING, &ua->flags);
	else
		clear_bit(COMMAND_PENDING, &ua->flags);

	return ret;
}

static const struct ucsi_operations ucsi_acpi_ops = {
	.read = ucsi_acpi_read,
	.sync_write = ucsi_acpi_sync_write,
	.async_write = ucsi_acpi_async_write
};

static int
ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len)
{
	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
	int ret;

	if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
		ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
		if (ret)
			return ret;
	}

	memcpy(val, ua->base + offset, val_len);

	return 0;
}

static const struct ucsi_operations ucsi_zenbook_ops = {
	.read = ucsi_zenbook_read,
	.sync_write = ucsi_acpi_sync_write,
	.async_write = ucsi_acpi_async_write
};

/*
 * Some Dell laptops expect that an ACK command with the
 * UCSI_ACK_CONNECTOR_CHANGE bit set is followed by a (separate)
 * ACK command that only has the UCSI_ACK_COMMAND_COMPLETE bit set.
 * If this is not done events are not delivered to OSPM and
 * subsequent commands will timeout.
 */
static int
ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset,
		     const void *val, size_t val_len)
{
	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
	u64 cmd = *(u64 *)val, ack = 0;
	int ret;

	if (UCSI_COMMAND(cmd) == UCSI_ACK_CC_CI &&
	    cmd & UCSI_ACK_CONNECTOR_CHANGE)
		ack = UCSI_ACK_CC_CI | UCSI_ACK_COMMAND_COMPLETE;

	ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
	if (ret != 0)
		return ret;
	if (ack == 0)
		return ret;

	if (!ua->dell_quirk_probed) {
		ua->dell_quirk_probed = true;

		cmd = UCSI_GET_CAPABILITY;
		ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd,
					   sizeof(cmd));
		if (ret == 0)
			return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL,
						    &ack, sizeof(ack));
		if (ret != -ETIMEDOUT)
			return ret;

		ua->dell_quirk_active = true;
		dev_err(ua->dev, "Firmware bug: Additional ACK required after ACKing a connector change.\n");
		dev_err(ua->dev, "Firmware bug: Enabling workaround\n");
	}

	if (!ua->dell_quirk_active)
		return ret;

	return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &ack, sizeof(ack));
}

static const struct ucsi_operations ucsi_dell_ops = {
	.read = ucsi_acpi_read,
	.sync_write = ucsi_dell_sync_write,
	.async_write = ucsi_acpi_async_write
};

static const struct dmi_system_id ucsi_acpi_quirks[] = {
	{
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
		},
		.driver_data = (void *)&ucsi_zenbook_ops,
	},
	{
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
		},
		.driver_data = (void *)&ucsi_dell_ops,
	},
	{ }
};

static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
{
	struct ucsi_acpi *ua = data;
	u32 cci;
	int ret;

	ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci));
	if (ret)
		return;

	if (UCSI_CCI_CONNECTOR(cci))
		ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));

	if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags))
		complete(&ua->complete);
	if (cci & UCSI_CCI_COMMAND_COMPLETE &&
	    test_bit(COMMAND_PENDING, &ua->flags))
		complete(&ua->complete);
}

static int ucsi_acpi_probe(struct platform_device *pdev)
{
	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
	const struct ucsi_operations *ops = &ucsi_acpi_ops;
	const struct dmi_system_id *id;
	struct ucsi_acpi *ua;
	struct resource *res;
	acpi_status status;
	int ret;

	if (adev->dep_unmet)
		return -EPROBE_DEFER;

	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;
	}

	ua->base = devm_memremap(&pdev->dev, res->start, resource_size(res), MEMREMAP_WB);
	if (IS_ERR(ua->base))
		return PTR_ERR(ua->base);

	ret = guid_parse(UCSI_DSM_UUID, &ua->guid);
	if (ret)
		return ret;

	init_completion(&ua->complete);
	ua->dev = &pdev->dev;

	id = dmi_first_match(ucsi_acpi_quirks);
	if (id)
		ops = id->driver_data;

	ua->ucsi = ucsi_create(&pdev->dev, ops);
	if (IS_ERR(ua->ucsi))
		return PTR_ERR(ua->ucsi);

	ucsi_set_drvdata(ua->ucsi, ua);

	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");
		ucsi_destroy(ua->ucsi);
		return -ENODEV;
	}

	ret = ucsi_register(ua->ucsi);
	if (ret) {
		acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
					   ACPI_DEVICE_NOTIFY,
					   ucsi_acpi_notify);
		ucsi_destroy(ua->ucsi);
		return ret;
	}

	platform_set_drvdata(pdev, ua);

	return 0;
}

static void ucsi_acpi_remove(struct platform_device *pdev)
{
	struct ucsi_acpi *ua = platform_get_drvdata(pdev);

	ucsi_unregister(ua->ucsi);
	ucsi_destroy(ua->ucsi);

	acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY,
				   ucsi_acpi_notify);
}

static int ucsi_acpi_resume(struct device *dev)
{
	struct ucsi_acpi *ua = dev_get_drvdata(dev);

	return ucsi_resume(ua->ucsi);
}

static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume);

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",
		.pm = pm_ptr(&ucsi_acpi_pm_ops),
		.acpi_match_table = ACPI_PTR(ucsi_acpi_match),
	},
	.probe = ucsi_acpi_probe,
	.remove_new = 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");
