18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Synopsys DesignWare I2C adapter driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on the TI DAVINCI I2C adapter driver.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2006 Texas Instruments.
88c2ecf20Sopenharmony_ci * Copyright (C) 2007 MontaVista Software Inc.
98c2ecf20Sopenharmony_ci * Copyright (C) 2009 Provigent Ltd.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/acpi.h>
128c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
138c2ecf20Sopenharmony_ci#include <linux/clk.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/dmi.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/errno.h>
188c2ecf20Sopenharmony_ci#include <linux/i2c.h>
198c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
238c2ecf20Sopenharmony_ci#include <linux/module.h>
248c2ecf20Sopenharmony_ci#include <linux/of.h>
258c2ecf20Sopenharmony_ci#include <linux/platform_data/i2c-designware.h>
268c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
278c2ecf20Sopenharmony_ci#include <linux/pm.h>
288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
298c2ecf20Sopenharmony_ci#include <linux/property.h>
308c2ecf20Sopenharmony_ci#include <linux/regmap.h>
318c2ecf20Sopenharmony_ci#include <linux/reset.h>
328c2ecf20Sopenharmony_ci#include <linux/sched.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci#include <linux/suspend.h>
358c2ecf20Sopenharmony_ci#include <linux/units.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "i2c-designware-core.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return clk_get_rate(dev->clk) / KILO;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
458c2ecf20Sopenharmony_cistatic const struct acpi_device_id dw_i2c_acpi_match[] = {
468c2ecf20Sopenharmony_ci	{ "INT33C2", 0 },
478c2ecf20Sopenharmony_ci	{ "INT33C3", 0 },
488c2ecf20Sopenharmony_ci	{ "INT3432", 0 },
498c2ecf20Sopenharmony_ci	{ "INT3433", 0 },
508c2ecf20Sopenharmony_ci	{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
518c2ecf20Sopenharmony_ci	{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
528c2ecf20Sopenharmony_ci	{ "AMD0010", ACCESS_INTR_MASK },
538c2ecf20Sopenharmony_ci	{ "AMDI0010", ACCESS_INTR_MASK },
548c2ecf20Sopenharmony_ci	{ "AMDI0510", 0 },
558c2ecf20Sopenharmony_ci	{ "APMC0D0F", 0 },
568c2ecf20Sopenharmony_ci	{ "HISI02A1", 0 },
578c2ecf20Sopenharmony_ci	{ "HISI02A2", 0 },
588c2ecf20Sopenharmony_ci	{ "HISI02A3", 0 },
598c2ecf20Sopenharmony_ci	{ "HYGO0010", ACCESS_INTR_MASK },
608c2ecf20Sopenharmony_ci	{ }
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
668c2ecf20Sopenharmony_ci#define BT1_I2C_CTL			0x100
678c2ecf20Sopenharmony_ci#define BT1_I2C_CTL_ADDR_MASK		GENMASK(7, 0)
688c2ecf20Sopenharmony_ci#define BT1_I2C_CTL_WR			BIT(8)
698c2ecf20Sopenharmony_ci#define BT1_I2C_CTL_GO			BIT(31)
708c2ecf20Sopenharmony_ci#define BT1_I2C_DI			0x104
718c2ecf20Sopenharmony_ci#define BT1_I2C_DO			0x108
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct dw_i2c_dev *dev = context;
768c2ecf20Sopenharmony_ci	int ret;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/*
798c2ecf20Sopenharmony_ci	 * Note these methods shouldn't ever fail because the system controller
808c2ecf20Sopenharmony_ci	 * registers are memory mapped. We check the return value just in case.
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
838c2ecf20Sopenharmony_ci			   BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
848c2ecf20Sopenharmony_ci	if (ret)
858c2ecf20Sopenharmony_ci		return ret;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return regmap_read(dev->sysmap, BT1_I2C_DO, val);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct dw_i2c_dev *dev = context;
938c2ecf20Sopenharmony_ci	int ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
968c2ecf20Sopenharmony_ci	if (ret)
978c2ecf20Sopenharmony_ci		return ret;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return regmap_write(dev->sysmap, BT1_I2C_CTL,
1008c2ecf20Sopenharmony_ci		BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic struct regmap_config bt1_i2c_cfg = {
1048c2ecf20Sopenharmony_ci	.reg_bits = 32,
1058c2ecf20Sopenharmony_ci	.val_bits = 32,
1068c2ecf20Sopenharmony_ci	.reg_stride = 4,
1078c2ecf20Sopenharmony_ci	.fast_io = true,
1088c2ecf20Sopenharmony_ci	.reg_read = bt1_i2c_read,
1098c2ecf20Sopenharmony_ci	.reg_write = bt1_i2c_write,
1108c2ecf20Sopenharmony_ci	.max_register = DW_IC_COMP_TYPE,
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
1168c2ecf20Sopenharmony_ci	if (IS_ERR(dev->sysmap))
1178c2ecf20Sopenharmony_ci		return PTR_ERR(dev->sysmap);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
1208c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(dev->map);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_DELAY		0x0
1248c2ecf20Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE	BIT(0)
1258c2ecf20Sopenharmony_ci#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER	0x4
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
1308c2ecf20Sopenharmony_ci	       dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic int dw_i2c_of_configure(struct platform_device *pdev)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	switch (dev->flags & MODEL_MASK) {
1408c2ecf20Sopenharmony_ci	case MODEL_MSCC_OCELOT:
1418c2ecf20Sopenharmony_ci		dev->ext = devm_platform_ioremap_resource(pdev, 1);
1428c2ecf20Sopenharmony_ci		if (!IS_ERR(dev->ext))
1438c2ecf20Sopenharmony_ci			dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
1448c2ecf20Sopenharmony_ci		break;
1458c2ecf20Sopenharmony_ci	default:
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const struct of_device_id dw_i2c_of_match[] = {
1538c2ecf20Sopenharmony_ci	{ .compatible = "snps,designware-i2c", },
1548c2ecf20Sopenharmony_ci	{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
1558c2ecf20Sopenharmony_ci	{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
1568c2ecf20Sopenharmony_ci	{},
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dw_i2c_of_match);
1598c2ecf20Sopenharmony_ci#else
1608c2ecf20Sopenharmony_cistatic int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	return -ENODEV;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline int dw_i2c_of_configure(struct platform_device *pdev)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	return -ENODEV;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci#endif
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	pm_runtime_disable(dev->dev);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (dev->shared_with_punit)
1768c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(dev->dev);
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev->dev);
1828c2ecf20Sopenharmony_ci	int ret;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	switch (dev->flags & MODEL_MASK) {
1858c2ecf20Sopenharmony_ci	case MODEL_BAIKAL_BT1:
1868c2ecf20Sopenharmony_ci		ret = bt1_i2c_request_regs(dev);
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci	default:
1898c2ecf20Sopenharmony_ci		dev->base = devm_platform_ioremap_resource(pdev, 0);
1908c2ecf20Sopenharmony_ci		ret = PTR_ERR_OR_ZERO(dev->base);
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return ret;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
1988c2ecf20Sopenharmony_ci	{
1998c2ecf20Sopenharmony_ci		.ident = "Qtechnology QT5222",
2008c2ecf20Sopenharmony_ci		.matches = {
2018c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology"),
2028c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "QT5222"),
2038c2ecf20Sopenharmony_ci		},
2048c2ecf20Sopenharmony_ci	},
2058c2ecf20Sopenharmony_ci	{ } /* terminate list */
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int dw_i2c_plat_probe(struct platform_device *pdev)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
2118c2ecf20Sopenharmony_ci	struct i2c_adapter *adap;
2128c2ecf20Sopenharmony_ci	struct dw_i2c_dev *dev;
2138c2ecf20Sopenharmony_ci	struct i2c_timings *t;
2148c2ecf20Sopenharmony_ci	int irq, ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
2178c2ecf20Sopenharmony_ci	if (irq < 0)
2188c2ecf20Sopenharmony_ci		return irq;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
2218c2ecf20Sopenharmony_ci	if (!dev)
2228c2ecf20Sopenharmony_ci		return -ENOMEM;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
2258c2ecf20Sopenharmony_ci	dev->dev = &pdev->dev;
2268c2ecf20Sopenharmony_ci	dev->irq = irq;
2278c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, dev);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	ret = dw_i2c_plat_request_regs(dev);
2308c2ecf20Sopenharmony_ci	if (ret)
2318c2ecf20Sopenharmony_ci		return ret;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
2348c2ecf20Sopenharmony_ci	if (IS_ERR(dev->rst))
2358c2ecf20Sopenharmony_ci		return PTR_ERR(dev->rst);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	reset_control_deassert(dev->rst);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	t = &dev->timings;
2408c2ecf20Sopenharmony_ci	if (pdata)
2418c2ecf20Sopenharmony_ci		t->bus_freq_hz = pdata->i2c_scl_freq;
2428c2ecf20Sopenharmony_ci	else
2438c2ecf20Sopenharmony_ci		i2c_parse_fw_timings(&pdev->dev, t, false);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	i2c_dw_adjust_bus_speed(dev);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (pdev->dev.of_node)
2488c2ecf20Sopenharmony_ci		dw_i2c_of_configure(pdev);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (has_acpi_companion(&pdev->dev))
2518c2ecf20Sopenharmony_ci		i2c_dw_acpi_configure(&pdev->dev);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	ret = i2c_dw_validate_speed(dev);
2548c2ecf20Sopenharmony_ci	if (ret)
2558c2ecf20Sopenharmony_ci		goto exit_reset;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	ret = i2c_dw_probe_lock_support(dev);
2588c2ecf20Sopenharmony_ci	if (ret)
2598c2ecf20Sopenharmony_ci		goto exit_reset;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	i2c_dw_configure(dev);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Optional interface clock */
2648c2ecf20Sopenharmony_ci	dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
2658c2ecf20Sopenharmony_ci	if (IS_ERR(dev->pclk)) {
2668c2ecf20Sopenharmony_ci		ret = PTR_ERR(dev->pclk);
2678c2ecf20Sopenharmony_ci		goto exit_reset;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dev->clk = devm_clk_get_optional(&pdev->dev, NULL);
2718c2ecf20Sopenharmony_ci	if (IS_ERR(dev->clk)) {
2728c2ecf20Sopenharmony_ci		ret = PTR_ERR(dev->clk);
2738c2ecf20Sopenharmony_ci		goto exit_reset;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ret = i2c_dw_prepare_clk(dev, true);
2778c2ecf20Sopenharmony_ci	if (ret)
2788c2ecf20Sopenharmony_ci		goto exit_reset;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (dev->clk) {
2818c2ecf20Sopenharmony_ci		u64 clk_khz;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
2848c2ecf20Sopenharmony_ci		clk_khz = dev->get_clk_rate_khz(dev);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		if (!dev->sda_hold_time && t->sda_hold_ns)
2878c2ecf20Sopenharmony_ci			dev->sda_hold_time =
2888c2ecf20Sopenharmony_ci				DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	adap = &dev->adapter;
2928c2ecf20Sopenharmony_ci	adap->owner = THIS_MODULE;
2938c2ecf20Sopenharmony_ci	adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?
2948c2ecf20Sopenharmony_ci					I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
2958c2ecf20Sopenharmony_ci	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
2968c2ecf20Sopenharmony_ci	adap->dev.of_node = pdev->dev.of_node;
2978c2ecf20Sopenharmony_ci	adap->nr = -1;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
3008c2ecf20Sopenharmony_ci		dev_pm_set_driver_flags(&pdev->dev,
3018c2ecf20Sopenharmony_ci					DPM_FLAG_SMART_PREPARE |
3028c2ecf20Sopenharmony_ci					DPM_FLAG_MAY_SKIP_RESUME);
3038c2ecf20Sopenharmony_ci	} else {
3048c2ecf20Sopenharmony_ci		dev_pm_set_driver_flags(&pdev->dev,
3058c2ecf20Sopenharmony_ci					DPM_FLAG_SMART_PREPARE |
3068c2ecf20Sopenharmony_ci					DPM_FLAG_SMART_SUSPEND |
3078c2ecf20Sopenharmony_ci					DPM_FLAG_MAY_SKIP_RESUME);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* The code below assumes runtime PM to be disabled. */
3118c2ecf20Sopenharmony_ci	WARN_ON(pm_runtime_enabled(&pdev->dev));
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
3148c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
3158c2ecf20Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (dev->shared_with_punit)
3188c2ecf20Sopenharmony_ci		pm_runtime_get_noresume(&pdev->dev);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	ret = i2c_dw_probe(dev);
3238c2ecf20Sopenharmony_ci	if (ret)
3248c2ecf20Sopenharmony_ci		goto exit_probe;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return ret;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ciexit_probe:
3298c2ecf20Sopenharmony_ci	dw_i2c_plat_pm_cleanup(dev);
3308c2ecf20Sopenharmony_ciexit_reset:
3318c2ecf20Sopenharmony_ci	reset_control_assert(dev->rst);
3328c2ecf20Sopenharmony_ci	return ret;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int dw_i2c_plat_remove(struct platform_device *pdev)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&pdev->dev);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	i2c_del_adapter(&dev->adapter);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	dev->disable(dev);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
3468c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
3478c2ecf20Sopenharmony_ci	dw_i2c_plat_pm_cleanup(dev);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	reset_control_assert(dev->rst);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
3558c2ecf20Sopenharmony_cistatic int dw_i2c_plat_prepare(struct device *dev)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	/*
3588c2ecf20Sopenharmony_ci	 * If the ACPI companion device object is present for this device, it
3598c2ecf20Sopenharmony_ci	 * may be accessed during suspend and resume of other devices via I2C
3608c2ecf20Sopenharmony_ci	 * operation regions, so tell the PM core and middle layers to avoid
3618c2ecf20Sopenharmony_ci	 * skipping system suspend/resume callbacks for it in that case.
3628c2ecf20Sopenharmony_ci	 */
3638c2ecf20Sopenharmony_ci	return !has_acpi_companion(dev);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic void dw_i2c_plat_complete(struct device *dev)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	/*
3698c2ecf20Sopenharmony_ci	 * The device can only be in runtime suspend at this point if it has not
3708c2ecf20Sopenharmony_ci	 * been resumed throughout the ending system suspend/resume cycle, so if
3718c2ecf20Sopenharmony_ci	 * the platform firmware might mess up with it, request the runtime PM
3728c2ecf20Sopenharmony_ci	 * framework to resume it.
3738c2ecf20Sopenharmony_ci	 */
3748c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
3758c2ecf20Sopenharmony_ci		pm_request_resume(dev);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci#else
3788c2ecf20Sopenharmony_ci#define dw_i2c_plat_prepare	NULL
3798c2ecf20Sopenharmony_ci#define dw_i2c_plat_complete	NULL
3808c2ecf20Sopenharmony_ci#endif
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
3838c2ecf20Sopenharmony_cistatic int dw_i2c_plat_suspend(struct device *dev)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	i_dev->suspended = true;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (i_dev->shared_with_punit)
3908c2ecf20Sopenharmony_ci		return 0;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	i_dev->disable(i_dev);
3938c2ecf20Sopenharmony_ci	i2c_dw_prepare_clk(i_dev, false);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	return 0;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic int dw_i2c_plat_resume(struct device *dev)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (!i_dev->shared_with_punit)
4038c2ecf20Sopenharmony_ci		i2c_dw_prepare_clk(i_dev, true);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	i_dev->init(i_dev);
4068c2ecf20Sopenharmony_ci	i_dev->suspended = false;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dw_i2c_dev_pm_ops = {
4128c2ecf20Sopenharmony_ci	.prepare = dw_i2c_plat_prepare,
4138c2ecf20Sopenharmony_ci	.complete = dw_i2c_plat_complete,
4148c2ecf20Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
4158c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
4198c2ecf20Sopenharmony_ci#else
4208c2ecf20Sopenharmony_ci#define DW_I2C_DEV_PMOPS NULL
4218c2ecf20Sopenharmony_ci#endif
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci/* Work with hotplug and coldplug */
4248c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:i2c_designware");
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic struct platform_driver dw_i2c_driver = {
4278c2ecf20Sopenharmony_ci	.probe = dw_i2c_plat_probe,
4288c2ecf20Sopenharmony_ci	.remove = dw_i2c_plat_remove,
4298c2ecf20Sopenharmony_ci	.driver		= {
4308c2ecf20Sopenharmony_ci		.name	= "i2c_designware",
4318c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(dw_i2c_of_match),
4328c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
4338c2ecf20Sopenharmony_ci		.pm	= DW_I2C_DEV_PMOPS,
4348c2ecf20Sopenharmony_ci	},
4358c2ecf20Sopenharmony_ci};
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int __init dw_i2c_init_driver(void)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	return platform_driver_register(&dw_i2c_driver);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_cisubsys_initcall(dw_i2c_init_driver);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void __exit dw_i2c_exit_driver(void)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	platform_driver_unregister(&dw_i2c_driver);
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_cimodule_exit(dw_i2c_exit_driver);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
4508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
4518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
452