18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AMD MP2 platform driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Setup the I2C adapters enumerated in the ACPI namespace.
68c2ecf20Sopenharmony_ci * MP2 controllers have 2 separate busses, up to 2 I2C adapters may be listed.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
98c2ecf20Sopenharmony_ci *          Elie Morisse <syniurge@gmail.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/acpi.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "i2c-amd-mp2.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define AMD_MP2_I2C_MAX_RW_LENGTH ((1 << 12) - 1)
228c2ecf20Sopenharmony_ci#define AMD_I2C_TIMEOUT (msecs_to_jiffies(250))
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * struct amd_i2c_dev - MP2 bus/i2c adapter context
268c2ecf20Sopenharmony_ci * @common: shared context with the MP2 PCI driver
278c2ecf20Sopenharmony_ci * @pdev: platform driver node
288c2ecf20Sopenharmony_ci * @adap: i2c adapter
298c2ecf20Sopenharmony_ci * @cmd_complete: xfer completion object
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistruct amd_i2c_dev {
328c2ecf20Sopenharmony_ci	struct amd_i2c_common common;
338c2ecf20Sopenharmony_ci	struct platform_device *pdev;
348c2ecf20Sopenharmony_ci	struct i2c_adapter adap;
358c2ecf20Sopenharmony_ci	struct completion cmd_complete;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define amd_i2c_dev_common(__common) \
398c2ecf20Sopenharmony_ci	container_of(__common, struct amd_i2c_dev, common)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int i2c_amd_dma_map(struct amd_i2c_common *i2c_common)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
448c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
458c2ecf20Sopenharmony_ci	enum dma_data_direction dma_direction =
468c2ecf20Sopenharmony_ci			i2c_common->msg->flags & I2C_M_RD ?
478c2ecf20Sopenharmony_ci			DMA_FROM_DEVICE : DMA_TO_DEVICE;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	i2c_common->dma_buf = i2c_get_dma_safe_msg_buf(i2c_common->msg, 0);
508c2ecf20Sopenharmony_ci	i2c_common->dma_addr = dma_map_single(dev_pci, i2c_common->dma_buf,
518c2ecf20Sopenharmony_ci					      i2c_common->msg->len,
528c2ecf20Sopenharmony_ci					      dma_direction);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(dev_pci, i2c_common->dma_addr))) {
558c2ecf20Sopenharmony_ci		dev_err(&i2c_dev->pdev->dev,
568c2ecf20Sopenharmony_ci			"Error while mapping dma buffer %p\n",
578c2ecf20Sopenharmony_ci			i2c_common->dma_buf);
588c2ecf20Sopenharmony_ci		return -EIO;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return 0;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void i2c_amd_dma_unmap(struct amd_i2c_common *i2c_common)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct device *dev_pci = &i2c_common->mp2_dev->pci_dev->dev;
678c2ecf20Sopenharmony_ci	enum dma_data_direction dma_direction =
688c2ecf20Sopenharmony_ci			i2c_common->msg->flags & I2C_M_RD ?
698c2ecf20Sopenharmony_ci			DMA_FROM_DEVICE : DMA_TO_DEVICE;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	dma_unmap_single(dev_pci, i2c_common->dma_addr,
728c2ecf20Sopenharmony_ci			 i2c_common->msg->len, dma_direction);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	i2c_put_dma_safe_msg_buf(i2c_common->dma_buf, i2c_common->msg, true);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void i2c_amd_start_cmd(struct amd_i2c_dev *i2c_dev)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct amd_i2c_common *i2c_common = &i2c_dev->common;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	reinit_completion(&i2c_dev->cmd_complete);
828c2ecf20Sopenharmony_ci	i2c_common->cmd_success = false;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
888c2ecf20Sopenharmony_ci	union i2c_event *event = &i2c_common->eventval;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (event->r.status == i2c_readcomplete_event)
918c2ecf20Sopenharmony_ci		dev_dbg(&i2c_dev->pdev->dev, "%s readdata:%*ph\n",
928c2ecf20Sopenharmony_ci			__func__, event->r.length,
938c2ecf20Sopenharmony_ci			i2c_common->msg->buf);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	complete(&i2c_dev->cmd_complete);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct amd_i2c_common *i2c_common = &i2c_dev->common;
1018c2ecf20Sopenharmony_ci	unsigned long timeout;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	timeout = wait_for_completion_timeout(&i2c_dev->cmd_complete,
1048c2ecf20Sopenharmony_ci					      i2c_dev->adap.timeout);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if ((i2c_common->reqcmd == i2c_read ||
1078c2ecf20Sopenharmony_ci	     i2c_common->reqcmd == i2c_write) &&
1088c2ecf20Sopenharmony_ci	    i2c_common->msg->len > 32)
1098c2ecf20Sopenharmony_ci		i2c_amd_dma_unmap(i2c_common);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (timeout == 0) {
1128c2ecf20Sopenharmony_ci		amd_mp2_rw_timeout(i2c_common);
1138c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	amd_mp2_process_event(i2c_common);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (!i2c_common->cmd_success)
1198c2ecf20Sopenharmony_ci		return -EIO;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int i2c_amd_enable_set(struct amd_i2c_dev *i2c_dev, bool enable)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct amd_i2c_common *i2c_common = &i2c_dev->common;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	i2c_amd_start_cmd(i2c_dev);
1298c2ecf20Sopenharmony_ci	amd_mp2_bus_enable_set(i2c_common, enable);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return i2c_amd_check_cmd_completion(i2c_dev);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int i2c_amd_xfer_msg(struct amd_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct amd_i2c_common *i2c_common = &i2c_dev->common;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	i2c_amd_start_cmd(i2c_dev);
1398c2ecf20Sopenharmony_ci	i2c_common->msg = pmsg;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (pmsg->len > 32)
1428c2ecf20Sopenharmony_ci		if (i2c_amd_dma_map(i2c_common))
1438c2ecf20Sopenharmony_ci			return -EIO;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (pmsg->flags & I2C_M_RD)
1468c2ecf20Sopenharmony_ci		amd_mp2_rw(i2c_common, i2c_read);
1478c2ecf20Sopenharmony_ci	else
1488c2ecf20Sopenharmony_ci		amd_mp2_rw(i2c_common, i2c_write);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return i2c_amd_check_cmd_completion(i2c_dev);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int i2c_amd_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
1568c2ecf20Sopenharmony_ci	int i;
1578c2ecf20Sopenharmony_ci	struct i2c_msg *pmsg;
1588c2ecf20Sopenharmony_ci	int err = 0;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* the adapter might have been deleted while waiting for the bus lock */
1618c2ecf20Sopenharmony_ci	if (unlikely(!i2c_dev->common.mp2_dev))
1628c2ecf20Sopenharmony_ci		return -EINVAL;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	amd_mp2_pm_runtime_get(i2c_dev->common.mp2_dev);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
1678c2ecf20Sopenharmony_ci		pmsg = &msgs[i];
1688c2ecf20Sopenharmony_ci		err = i2c_amd_xfer_msg(i2c_dev, pmsg);
1698c2ecf20Sopenharmony_ci		if (err)
1708c2ecf20Sopenharmony_ci			break;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	amd_mp2_pm_runtime_put(i2c_dev->common.mp2_dev);
1748c2ecf20Sopenharmony_ci	return err ? err : num;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic u32 i2c_amd_func(struct i2c_adapter *a)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const struct i2c_algorithm i2c_amd_algorithm = {
1838c2ecf20Sopenharmony_ci	.master_xfer = i2c_amd_xfer,
1848c2ecf20Sopenharmony_ci	.functionality = i2c_amd_func,
1858c2ecf20Sopenharmony_ci};
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1888c2ecf20Sopenharmony_cistatic int i2c_amd_suspend(struct amd_i2c_common *i2c_common)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	i2c_amd_enable_set(i2c_dev, false);
1938c2ecf20Sopenharmony_ci	return 0;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int i2c_amd_resume(struct amd_i2c_common *i2c_common)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = amd_i2c_dev_common(i2c_common);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return i2c_amd_enable_set(i2c_dev, true);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci#endif
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic const u32 supported_speeds[] = {
2058c2ecf20Sopenharmony_ci	I2C_MAX_HIGH_SPEED_MODE_FREQ,
2068c2ecf20Sopenharmony_ci	I2C_MAX_TURBO_MODE_FREQ,
2078c2ecf20Sopenharmony_ci	I2C_MAX_FAST_MODE_PLUS_FREQ,
2088c2ecf20Sopenharmony_ci	I2C_MAX_FAST_MODE_FREQ,
2098c2ecf20Sopenharmony_ci	I2C_MAX_STANDARD_MODE_FREQ,
2108c2ecf20Sopenharmony_ci};
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic enum speed_enum i2c_amd_get_bus_speed(struct platform_device *pdev)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	u32 acpi_speed;
2158c2ecf20Sopenharmony_ci	int i;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
2188c2ecf20Sopenharmony_ci	/* round down to the lowest standard speed */
2198c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) {
2208c2ecf20Sopenharmony_ci		if (acpi_speed >= supported_speeds[i])
2218c2ecf20Sopenharmony_ci			break;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci	acpi_speed = i < ARRAY_SIZE(supported_speeds) ? supported_speeds[i] : 0;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	switch (acpi_speed) {
2268c2ecf20Sopenharmony_ci	case I2C_MAX_STANDARD_MODE_FREQ:
2278c2ecf20Sopenharmony_ci		return speed100k;
2288c2ecf20Sopenharmony_ci	case I2C_MAX_FAST_MODE_FREQ:
2298c2ecf20Sopenharmony_ci		return speed400k;
2308c2ecf20Sopenharmony_ci	case I2C_MAX_FAST_MODE_PLUS_FREQ:
2318c2ecf20Sopenharmony_ci		return speed1000k;
2328c2ecf20Sopenharmony_ci	case I2C_MAX_TURBO_MODE_FREQ:
2338c2ecf20Sopenharmony_ci		return speed1400k;
2348c2ecf20Sopenharmony_ci	case I2C_MAX_HIGH_SPEED_MODE_FREQ:
2358c2ecf20Sopenharmony_ci		return speed3400k;
2368c2ecf20Sopenharmony_ci	default:
2378c2ecf20Sopenharmony_ci		return speed400k;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic const struct i2c_adapter_quirks amd_i2c_dev_quirks = {
2428c2ecf20Sopenharmony_ci	.max_read_len = AMD_MP2_I2C_MAX_RW_LENGTH,
2438c2ecf20Sopenharmony_ci	.max_write_len = AMD_MP2_I2C_MAX_RW_LENGTH,
2448c2ecf20Sopenharmony_ci};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int i2c_amd_probe(struct platform_device *pdev)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	int ret;
2498c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev;
2508c2ecf20Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
2518c2ecf20Sopenharmony_ci	struct acpi_device *adev;
2528c2ecf20Sopenharmony_ci	struct amd_mp2_dev *mp2_dev;
2538c2ecf20Sopenharmony_ci	const char *uid;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (acpi_bus_get_device(handle, &adev))
2568c2ecf20Sopenharmony_ci		return -ENODEV;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	/* The ACPI namespace doesn't contain information about which MP2 PCI
2598c2ecf20Sopenharmony_ci	 * device an AMDI0011 ACPI device is related to, so assume that there's
2608c2ecf20Sopenharmony_ci	 * only one MP2 PCI device per system.
2618c2ecf20Sopenharmony_ci	 */
2628c2ecf20Sopenharmony_ci	mp2_dev = amd_mp2_find_device();
2638c2ecf20Sopenharmony_ci	if (!mp2_dev || !mp2_dev->probed)
2648c2ecf20Sopenharmony_ci		/* The MP2 PCI device should get probed later */
2658c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
2688c2ecf20Sopenharmony_ci	if (!i2c_dev)
2698c2ecf20Sopenharmony_ci		return -ENOMEM;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	i2c_dev->common.mp2_dev = mp2_dev;
2728c2ecf20Sopenharmony_ci	i2c_dev->pdev = pdev;
2738c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, i2c_dev);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	i2c_dev->common.cmd_completion = &i2c_amd_cmd_completion;
2768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
2778c2ecf20Sopenharmony_ci	i2c_dev->common.suspend = &i2c_amd_suspend;
2788c2ecf20Sopenharmony_ci	i2c_dev->common.resume = &i2c_amd_resume;
2798c2ecf20Sopenharmony_ci#endif
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	uid = adev->pnp.unique_id;
2828c2ecf20Sopenharmony_ci	if (!uid) {
2838c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing UID/bus id!\n");
2848c2ecf20Sopenharmony_ci		return -EINVAL;
2858c2ecf20Sopenharmony_ci	} else if (strcmp(uid, "0") == 0) {
2868c2ecf20Sopenharmony_ci		i2c_dev->common.bus_id = 0;
2878c2ecf20Sopenharmony_ci	} else if (strcmp(uid, "1") == 0) {
2888c2ecf20Sopenharmony_ci		i2c_dev->common.bus_id = 1;
2898c2ecf20Sopenharmony_ci	} else {
2908c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "incorrect UID/bus id \"%s\"!\n", uid);
2918c2ecf20Sopenharmony_ci		return -EINVAL;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "bus id is %u\n", i2c_dev->common.bus_id);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* Register the adapter */
2968c2ecf20Sopenharmony_ci	amd_mp2_pm_runtime_get(mp2_dev);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	i2c_dev->common.reqcmd = i2c_none;
2998c2ecf20Sopenharmony_ci	if (amd_mp2_register_cb(&i2c_dev->common))
3008c2ecf20Sopenharmony_ci		return -EINVAL;
3018c2ecf20Sopenharmony_ci	device_link_add(&i2c_dev->pdev->dev, &mp2_dev->pci_dev->dev,
3028c2ecf20Sopenharmony_ci			DL_FLAG_AUTOREMOVE_CONSUMER);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	i2c_dev->common.i2c_speed = i2c_amd_get_bus_speed(pdev);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* Setup i2c adapter description */
3078c2ecf20Sopenharmony_ci	i2c_dev->adap.owner = THIS_MODULE;
3088c2ecf20Sopenharmony_ci	i2c_dev->adap.algo = &i2c_amd_algorithm;
3098c2ecf20Sopenharmony_ci	i2c_dev->adap.quirks = &amd_i2c_dev_quirks;
3108c2ecf20Sopenharmony_ci	i2c_dev->adap.dev.parent = &pdev->dev;
3118c2ecf20Sopenharmony_ci	i2c_dev->adap.algo_data = i2c_dev;
3128c2ecf20Sopenharmony_ci	i2c_dev->adap.timeout = AMD_I2C_TIMEOUT;
3138c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(&i2c_dev->adap.dev, ACPI_COMPANION(&pdev->dev));
3148c2ecf20Sopenharmony_ci	i2c_dev->adap.dev.of_node = pdev->dev.of_node;
3158c2ecf20Sopenharmony_ci	snprintf(i2c_dev->adap.name, sizeof(i2c_dev->adap.name),
3168c2ecf20Sopenharmony_ci		 "AMD MP2 i2c bus %u", i2c_dev->common.bus_id);
3178c2ecf20Sopenharmony_ci	i2c_set_adapdata(&i2c_dev->adap, i2c_dev);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	init_completion(&i2c_dev->cmd_complete);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* Enable the bus */
3228c2ecf20Sopenharmony_ci	if (i2c_amd_enable_set(i2c_dev, true))
3238c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "initial bus enable failed\n");
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* Attach to the i2c layer */
3268c2ecf20Sopenharmony_ci	ret = i2c_add_adapter(&i2c_dev->adap);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	amd_mp2_pm_runtime_put(mp2_dev);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (ret < 0)
3318c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return ret;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int i2c_amd_remove(struct platform_device *pdev)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
3398c2ecf20Sopenharmony_ci	struct amd_i2c_common *i2c_common = &i2c_dev->common;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	i2c_amd_enable_set(i2c_dev, false);
3448c2ecf20Sopenharmony_ci	amd_mp2_unregister_cb(i2c_common);
3458c2ecf20Sopenharmony_ci	i2c_common->mp2_dev = NULL;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	i2c_del_adapter(&i2c_dev->adap);
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic const struct acpi_device_id i2c_amd_acpi_match[] = {
3548c2ecf20Sopenharmony_ci	{ "AMDI0011" },
3558c2ecf20Sopenharmony_ci	{ },
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic struct platform_driver i2c_amd_plat_driver = {
3608c2ecf20Sopenharmony_ci	.probe = i2c_amd_probe,
3618c2ecf20Sopenharmony_ci	.remove = i2c_amd_remove,
3628c2ecf20Sopenharmony_ci	.driver = {
3638c2ecf20Sopenharmony_ci		.name = "i2c_amd_mp2",
3648c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(i2c_amd_acpi_match),
3658c2ecf20Sopenharmony_ci	},
3668c2ecf20Sopenharmony_ci};
3678c2ecf20Sopenharmony_cimodule_platform_driver(i2c_amd_plat_driver);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD(R) MP2 I2C Platform Driver");
3708c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
3718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
3728c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
373