162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Synopsys DesignWare I2C adapter driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Based on the TI DAVINCI I2C adapter driver.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2006 Texas Instruments.
862306a36Sopenharmony_ci * Copyright (C) 2007 MontaVista Software Inc.
962306a36Sopenharmony_ci * Copyright (C) 2009 Provigent Ltd.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/acpi.h>
1262306a36Sopenharmony_ci#include <linux/clk-provider.h>
1362306a36Sopenharmony_ci#include <linux/clk.h>
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/dmi.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/errno.h>
1862306a36Sopenharmony_ci#include <linux/i2c.h>
1962306a36Sopenharmony_ci#include <linux/interrupt.h>
2062306a36Sopenharmony_ci#include <linux/io.h>
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci#include <linux/of.h>
2562306a36Sopenharmony_ci#include <linux/platform_device.h>
2662306a36Sopenharmony_ci#include <linux/pm.h>
2762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2862306a36Sopenharmony_ci#include <linux/property.h>
2962306a36Sopenharmony_ci#include <linux/regmap.h>
3062306a36Sopenharmony_ci#include <linux/reset.h>
3162306a36Sopenharmony_ci#include <linux/sched.h>
3262306a36Sopenharmony_ci#include <linux/slab.h>
3362306a36Sopenharmony_ci#include <linux/suspend.h>
3462306a36Sopenharmony_ci#include <linux/units.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "i2c-designware-core.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	return clk_get_rate(dev->clk) / KILO;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#ifdef CONFIG_ACPI
4462306a36Sopenharmony_cistatic const struct acpi_device_id dw_i2c_acpi_match[] = {
4562306a36Sopenharmony_ci	{ "INT33C2", 0 },
4662306a36Sopenharmony_ci	{ "INT33C3", 0 },
4762306a36Sopenharmony_ci	{ "INT3432", 0 },
4862306a36Sopenharmony_ci	{ "INT3433", 0 },
4962306a36Sopenharmony_ci	{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
5062306a36Sopenharmony_ci	{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
5162306a36Sopenharmony_ci	{ "AMD0010", ACCESS_INTR_MASK },
5262306a36Sopenharmony_ci	{ "AMDI0010", ACCESS_INTR_MASK },
5362306a36Sopenharmony_ci	{ "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
5462306a36Sopenharmony_ci	{ "AMDI0510", 0 },
5562306a36Sopenharmony_ci	{ "APMC0D0F", 0 },
5662306a36Sopenharmony_ci	{ "HISI02A1", 0 },
5762306a36Sopenharmony_ci	{ "HISI02A2", 0 },
5862306a36Sopenharmony_ci	{ "HISI02A3", 0 },
5962306a36Sopenharmony_ci	{ "HYGO0010", ACCESS_INTR_MASK },
6062306a36Sopenharmony_ci	{ }
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
6362306a36Sopenharmony_ci#endif
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#ifdef CONFIG_OF
6662306a36Sopenharmony_ci#define BT1_I2C_CTL			0x100
6762306a36Sopenharmony_ci#define BT1_I2C_CTL_ADDR_MASK		GENMASK(7, 0)
6862306a36Sopenharmony_ci#define BT1_I2C_CTL_WR			BIT(8)
6962306a36Sopenharmony_ci#define BT1_I2C_CTL_GO			BIT(31)
7062306a36Sopenharmony_ci#define BT1_I2C_DI			0x104
7162306a36Sopenharmony_ci#define BT1_I2C_DO			0x108
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct dw_i2c_dev *dev = context;
7662306a36Sopenharmony_ci	int ret;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * Note these methods shouldn't ever fail because the system controller
8062306a36Sopenharmony_ci	 * registers are memory mapped. We check the return value just in case.
8162306a36Sopenharmony_ci	 */
8262306a36Sopenharmony_ci	ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
8362306a36Sopenharmony_ci			   BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
8462306a36Sopenharmony_ci	if (ret)
8562306a36Sopenharmony_ci		return ret;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return regmap_read(dev->sysmap, BT1_I2C_DO, val);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct dw_i2c_dev *dev = context;
9362306a36Sopenharmony_ci	int ret;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
9662306a36Sopenharmony_ci	if (ret)
9762306a36Sopenharmony_ci		return ret;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return regmap_write(dev->sysmap, BT1_I2C_CTL,
10062306a36Sopenharmony_ci		BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic struct regmap_config bt1_i2c_cfg = {
10462306a36Sopenharmony_ci	.reg_bits = 32,
10562306a36Sopenharmony_ci	.val_bits = 32,
10662306a36Sopenharmony_ci	.reg_stride = 4,
10762306a36Sopenharmony_ci	.fast_io = true,
10862306a36Sopenharmony_ci	.reg_read = bt1_i2c_read,
10962306a36Sopenharmony_ci	.reg_write = bt1_i2c_write,
11062306a36Sopenharmony_ci	.max_register = DW_IC_COMP_TYPE,
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
11662306a36Sopenharmony_ci	if (IS_ERR(dev->sysmap))
11762306a36Sopenharmony_ci		return PTR_ERR(dev->sysmap);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
12062306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(dev->map);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_DELAY		0x0
12462306a36Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE	BIT(0)
12562306a36Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER	0x4
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
13062306a36Sopenharmony_ci	       dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int dw_i2c_of_configure(struct platform_device *pdev)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	switch (dev->flags & MODEL_MASK) {
14062306a36Sopenharmony_ci	case MODEL_MSCC_OCELOT:
14162306a36Sopenharmony_ci		dev->ext = devm_platform_ioremap_resource(pdev, 1);
14262306a36Sopenharmony_ci		if (!IS_ERR(dev->ext))
14362306a36Sopenharmony_ci			dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
14462306a36Sopenharmony_ci		break;
14562306a36Sopenharmony_ci	default:
14662306a36Sopenharmony_ci		break;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct of_device_id dw_i2c_of_match[] = {
15362306a36Sopenharmony_ci	{ .compatible = "snps,designware-i2c", },
15462306a36Sopenharmony_ci	{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
15562306a36Sopenharmony_ci	{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
15662306a36Sopenharmony_ci	{},
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dw_i2c_of_match);
15962306a36Sopenharmony_ci#else
16062306a36Sopenharmony_cistatic int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return -ENODEV;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic inline int dw_i2c_of_configure(struct platform_device *pdev)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return -ENODEV;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci#endif
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int txgbe_i2c_request_regs(struct dw_i2c_dev *dev)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	dev->map = dev_get_regmap(dev->dev->parent, NULL);
17462306a36Sopenharmony_ci	if (!dev->map)
17562306a36Sopenharmony_ci		return -ENODEV;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return 0;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	pm_runtime_disable(dev->dev);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (dev->shared_with_punit)
18562306a36Sopenharmony_ci		pm_runtime_put_noidle(dev->dev);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev->dev);
19162306a36Sopenharmony_ci	int ret;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	switch (dev->flags & MODEL_MASK) {
19462306a36Sopenharmony_ci	case MODEL_BAIKAL_BT1:
19562306a36Sopenharmony_ci		ret = bt1_i2c_request_regs(dev);
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	case MODEL_WANGXUN_SP:
19862306a36Sopenharmony_ci		ret = txgbe_i2c_request_regs(dev);
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	default:
20162306a36Sopenharmony_ci		dev->base = devm_platform_ioremap_resource(pdev, 0);
20262306a36Sopenharmony_ci		ret = PTR_ERR_OR_ZERO(dev->base);
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return ret;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
21062306a36Sopenharmony_ci	{
21162306a36Sopenharmony_ci		.ident = "Qtechnology QT5222",
21262306a36Sopenharmony_ci		.matches = {
21362306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology"),
21462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "QT5222"),
21562306a36Sopenharmony_ci		},
21662306a36Sopenharmony_ci	},
21762306a36Sopenharmony_ci	{ } /* terminate list */
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = {
22162306a36Sopenharmony_ci#ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL
22262306a36Sopenharmony_ci	{
22362306a36Sopenharmony_ci		.probe = i2c_dw_baytrail_probe_lock_support,
22462306a36Sopenharmony_ci	},
22562306a36Sopenharmony_ci#endif
22662306a36Sopenharmony_ci#ifdef CONFIG_I2C_DESIGNWARE_AMDPSP
22762306a36Sopenharmony_ci	{
22862306a36Sopenharmony_ci		.probe = i2c_dw_amdpsp_probe_lock_support,
22962306a36Sopenharmony_ci	},
23062306a36Sopenharmony_ci#endif
23162306a36Sopenharmony_ci	{}
23262306a36Sopenharmony_ci};
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	const struct i2c_dw_semaphore_callbacks *ptr;
23762306a36Sopenharmony_ci	int i = 0;
23862306a36Sopenharmony_ci	int ret;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ptr = i2c_dw_semaphore_cb_table;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	dev->semaphore_idx = -1;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	while (ptr->probe) {
24562306a36Sopenharmony_ci		ret = ptr->probe(dev);
24662306a36Sopenharmony_ci		if (ret) {
24762306a36Sopenharmony_ci			/*
24862306a36Sopenharmony_ci			 * If there is no semaphore device attached to this
24962306a36Sopenharmony_ci			 * controller, we shouldn't abort general i2c_controller
25062306a36Sopenharmony_ci			 * probe.
25162306a36Sopenharmony_ci			 */
25262306a36Sopenharmony_ci			if (ret != -ENODEV)
25362306a36Sopenharmony_ci				return ret;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci			i++;
25662306a36Sopenharmony_ci			ptr++;
25762306a36Sopenharmony_ci			continue;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		dev->semaphore_idx = i;
26162306a36Sopenharmony_ci		break;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	if (dev->semaphore_idx < 0)
27062306a36Sopenharmony_ci		return;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove)
27362306a36Sopenharmony_ci		i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int dw_i2c_plat_probe(struct platform_device *pdev)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct i2c_adapter *adap;
27962306a36Sopenharmony_ci	struct dw_i2c_dev *dev;
28062306a36Sopenharmony_ci	struct i2c_timings *t;
28162306a36Sopenharmony_ci	int irq, ret;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
28462306a36Sopenharmony_ci	if (irq < 0)
28562306a36Sopenharmony_ci		return irq;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
28862306a36Sopenharmony_ci	if (!dev)
28962306a36Sopenharmony_ci		return -ENOMEM;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
29262306a36Sopenharmony_ci	if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
29362306a36Sopenharmony_ci		dev->flags = MODEL_WANGXUN_SP;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	dev->dev = &pdev->dev;
29662306a36Sopenharmony_ci	dev->irq = irq;
29762306a36Sopenharmony_ci	platform_set_drvdata(pdev, dev);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	ret = dw_i2c_plat_request_regs(dev);
30062306a36Sopenharmony_ci	if (ret)
30162306a36Sopenharmony_ci		return ret;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
30462306a36Sopenharmony_ci	if (IS_ERR(dev->rst))
30562306a36Sopenharmony_ci		return PTR_ERR(dev->rst);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	reset_control_deassert(dev->rst);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	t = &dev->timings;
31062306a36Sopenharmony_ci	i2c_parse_fw_timings(&pdev->dev, t, false);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	i2c_dw_adjust_bus_speed(dev);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (pdev->dev.of_node)
31562306a36Sopenharmony_ci		dw_i2c_of_configure(pdev);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (has_acpi_companion(&pdev->dev))
31862306a36Sopenharmony_ci		i2c_dw_acpi_configure(&pdev->dev);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	ret = i2c_dw_validate_speed(dev);
32162306a36Sopenharmony_ci	if (ret)
32262306a36Sopenharmony_ci		goto exit_reset;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	ret = i2c_dw_probe_lock_support(dev);
32562306a36Sopenharmony_ci	if (ret)
32662306a36Sopenharmony_ci		goto exit_reset;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	i2c_dw_configure(dev);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Optional interface clock */
33162306a36Sopenharmony_ci	dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
33262306a36Sopenharmony_ci	if (IS_ERR(dev->pclk)) {
33362306a36Sopenharmony_ci		ret = PTR_ERR(dev->pclk);
33462306a36Sopenharmony_ci		goto exit_reset;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	dev->clk = devm_clk_get_optional(&pdev->dev, NULL);
33862306a36Sopenharmony_ci	if (IS_ERR(dev->clk)) {
33962306a36Sopenharmony_ci		ret = PTR_ERR(dev->clk);
34062306a36Sopenharmony_ci		goto exit_reset;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	ret = i2c_dw_prepare_clk(dev, true);
34462306a36Sopenharmony_ci	if (ret)
34562306a36Sopenharmony_ci		goto exit_reset;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (dev->clk) {
34862306a36Sopenharmony_ci		u64 clk_khz;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
35162306a36Sopenharmony_ci		clk_khz = dev->get_clk_rate_khz(dev);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		if (!dev->sda_hold_time && t->sda_hold_ns)
35462306a36Sopenharmony_ci			dev->sda_hold_time =
35562306a36Sopenharmony_ci				DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	adap = &dev->adapter;
35962306a36Sopenharmony_ci	adap->owner = THIS_MODULE;
36062306a36Sopenharmony_ci	adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?
36162306a36Sopenharmony_ci					I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
36262306a36Sopenharmony_ci	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
36362306a36Sopenharmony_ci	adap->dev.of_node = pdev->dev.of_node;
36462306a36Sopenharmony_ci	adap->nr = -1;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
36762306a36Sopenharmony_ci		dev_pm_set_driver_flags(&pdev->dev,
36862306a36Sopenharmony_ci					DPM_FLAG_SMART_PREPARE);
36962306a36Sopenharmony_ci	} else {
37062306a36Sopenharmony_ci		dev_pm_set_driver_flags(&pdev->dev,
37162306a36Sopenharmony_ci					DPM_FLAG_SMART_PREPARE |
37262306a36Sopenharmony_ci					DPM_FLAG_SMART_SUSPEND);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	device_enable_async_suspend(&pdev->dev);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* The code below assumes runtime PM to be disabled. */
37862306a36Sopenharmony_ci	WARN_ON(pm_runtime_enabled(&pdev->dev));
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
38162306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
38262306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (dev->shared_with_punit)
38562306a36Sopenharmony_ci		pm_runtime_get_noresume(&pdev->dev);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	ret = i2c_dw_probe(dev);
39062306a36Sopenharmony_ci	if (ret)
39162306a36Sopenharmony_ci		goto exit_probe;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return ret;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciexit_probe:
39662306a36Sopenharmony_ci	dw_i2c_plat_pm_cleanup(dev);
39762306a36Sopenharmony_ciexit_reset:
39862306a36Sopenharmony_ci	reset_control_assert(dev->rst);
39962306a36Sopenharmony_ci	return ret;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void dw_i2c_plat_remove(struct platform_device *pdev)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	i2c_del_adapter(&dev->adapter);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	dev->disable(dev);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
41362306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
41462306a36Sopenharmony_ci	dw_i2c_plat_pm_cleanup(dev);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	i2c_dw_remove_lock_support(dev);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	reset_control_assert(dev->rst);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic int dw_i2c_plat_prepare(struct device *dev)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	/*
42462306a36Sopenharmony_ci	 * If the ACPI companion device object is present for this device, it
42562306a36Sopenharmony_ci	 * may be accessed during suspend and resume of other devices via I2C
42662306a36Sopenharmony_ci	 * operation regions, so tell the PM core and middle layers to avoid
42762306a36Sopenharmony_ci	 * skipping system suspend/resume callbacks for it in that case.
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci	return !has_acpi_companion(dev);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int dw_i2c_plat_runtime_suspend(struct device *dev)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (i_dev->shared_with_punit)
43762306a36Sopenharmony_ci		return 0;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	i_dev->disable(i_dev);
44062306a36Sopenharmony_ci	i2c_dw_prepare_clk(i_dev, false);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int dw_i2c_plat_suspend(struct device *dev)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	i2c_mark_adapter_suspended(&i_dev->adapter);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return dw_i2c_plat_runtime_suspend(dev);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int dw_i2c_plat_runtime_resume(struct device *dev)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (!i_dev->shared_with_punit)
45962306a36Sopenharmony_ci		i2c_dw_prepare_clk(i_dev, true);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	i_dev->init(i_dev);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int dw_i2c_plat_resume(struct device *dev)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	dw_i2c_plat_runtime_resume(dev);
47162306a36Sopenharmony_ci	i2c_mark_adapter_resumed(&i_dev->adapter);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return 0;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic const struct dev_pm_ops dw_i2c_dev_pm_ops = {
47762306a36Sopenharmony_ci	.prepare = pm_sleep_ptr(dw_i2c_plat_prepare),
47862306a36Sopenharmony_ci	LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
47962306a36Sopenharmony_ci	RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL)
48062306a36Sopenharmony_ci};
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/* Work with hotplug and coldplug */
48362306a36Sopenharmony_ciMODULE_ALIAS("platform:i2c_designware");
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic struct platform_driver dw_i2c_driver = {
48662306a36Sopenharmony_ci	.probe = dw_i2c_plat_probe,
48762306a36Sopenharmony_ci	.remove_new = dw_i2c_plat_remove,
48862306a36Sopenharmony_ci	.driver		= {
48962306a36Sopenharmony_ci		.name	= "i2c_designware",
49062306a36Sopenharmony_ci		.of_match_table = of_match_ptr(dw_i2c_of_match),
49162306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
49262306a36Sopenharmony_ci		.pm	= pm_ptr(&dw_i2c_dev_pm_ops),
49362306a36Sopenharmony_ci	},
49462306a36Sopenharmony_ci};
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int __init dw_i2c_init_driver(void)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	return platform_driver_register(&dw_i2c_driver);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_cisubsys_initcall(dw_i2c_init_driver);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void __exit dw_i2c_exit_driver(void)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	platform_driver_unregister(&dw_i2c_driver);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_cimodule_exit(dw_i2c_exit_driver);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ciMODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
50962306a36Sopenharmony_ciMODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
51062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
511