This commit is contained in:
Mark Brown
2026-07-31 13:59:35 +01:00
7 changed files with 153 additions and 29 deletions
+3 -1
View File
@@ -316,8 +316,10 @@ static int i2c_amd_probe(struct platform_device *pdev)
amd_mp2_pm_runtime_put(mp2_dev);
if (ret < 0)
if (ret < 0) {
dev_err(&pdev->dev, "i2c add adapter failed = %d\n", ret);
amd_mp2_unregister_cb(&i2c_dev->common);
}
return ret;
}
+11
View File
@@ -803,6 +803,17 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
}
if (!time_left && !iproc_i2c->xfer_is_done) {
/*
* The controller may fail to clear START_BUSY after a timeout,
* reset the controller to recover in that case.
*/
if (!!(iproc_i2c_rd_reg(iproc_i2c, M_CMD_OFFSET) &
BIT(M_CMD_START_BUSY_SHIFT))) {
bcm_iproc_i2c_enable_disable(iproc_i2c, false);
bcm_iproc_i2c_init(iproc_i2c);
bcm_iproc_i2c_enable_disable(iproc_i2c, true);
}
/* flush both TX/RX FIFOs */
val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
@@ -8,12 +8,14 @@
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*/
#include <linux/acpi.h>
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -130,6 +132,80 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return 0;
}
#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
/*
* Check whether an ACPI GpioInt resource's referenced GPIO controller
* has finished probing. Resources with no named controller (resource
* source string) are skipped, since they can't be resolved to a
* struct device.
*/
static int check_gpioint_resource(struct acpi_resource *ares, void *data)
{
struct acpi_resource_gpio *agpio;
struct acpi_device *gpio_adev;
struct device *gpio_dev;
acpi_handle handle;
acpi_status status;
if (!acpi_gpio_get_irq_resource(ares, &agpio))
return 1; /* not a GpioInt resource, skip */
if (!agpio->resource_source.string_length)
return 1; /* no named controller, skip */
status = acpi_get_handle(NULL, agpio->resource_source.string_ptr, &handle);
if (ACPI_FAILURE(status))
return 1;
gpio_adev = acpi_fetch_acpi_dev(handle);
if (!gpio_adev)
return 1;
struct gpio_device *gdev __free(gpio_device_put) =
gpio_device_find_by_fwnode(acpi_fwnode_handle(gpio_adev));
if (!gdev)
return -EPROBE_DEFER; /* controller not registered yet: abort walk */
gpio_dev = gpio_device_to_device(gdev)->parent;
guard(device)(gpio_dev);
if (!device_is_bound(gpio_dev))
return -EPROBE_DEFER; /* controller not bound yet: abort walk */
return 1; /* bound, skip adding to resource list, continue walk */
}
static int check_child_gpioint(struct acpi_device *adev, void *data)
{
LIST_HEAD(res_list);
int ret;
ret = acpi_dev_get_resources(adev, &res_list, check_gpioint_resource, NULL);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&res_list);
return 0;
}
static int i2c_dw_check_gpio_dependencies(struct device *dev)
{
struct acpi_device *adev;
adev = ACPI_COMPANION(dev);
if (!adev)
return 0;
return acpi_dev_for_each_child(adev, check_child_gpioint, NULL);
}
#else
static int i2c_dw_check_gpio_dependencies(struct device *dev)
{
return 0;
}
#endif /* CONFIG_ACPI && CONFIG_GPIOLIB */
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
u32 flags = (uintptr_t)device_get_match_data(&pdev->dev);
@@ -138,6 +214,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
struct dw_i2c_dev *dev;
int irq, ret;
ret = i2c_dw_check_gpio_dependencies(device);
if (ret)
return ret;
irq = platform_get_irq_optional(pdev, 0);
if (irq == -ENXIO)
flags |= ACCESS_POLLING;
+49 -5
View File
@@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
if (i2c_imx->slave)
return -EBUSY;
i2c_imx->slave = client;
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
/* Resume */
ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (ret < 0) {
@@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
return ret;
}
scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
i2c_imx->slave = client;
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
}
i2c_imx_slave_init(i2c_imx);
return 0;
@@ -958,6 +960,7 @@ static int i2c_imx_unreg_slave(struct i2c_client *client)
i2c_imx_reset_regs(i2c_imx);
hrtimer_cancel(&i2c_imx->slave_timer);
i2c_imx->slave = NULL;
/* Suspend */
@@ -1952,6 +1955,47 @@ static int i2c_imx_runtime_resume(struct device *dev)
return 0;
}
static int __maybe_unused i2c_imx_suspend_noirq(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
i2c_mark_adapter_suspended(&i2c_imx->adapter);
/*
* Cancel the slave timer before powering down to prevent
* i2c_imx_slave_timeout() from accessing hardware registers
* while the clock is disabled.
*/
hrtimer_cancel(&i2c_imx->slave_timer);
ret = pm_runtime_force_suspend(dev);
if (ret) {
i2c_mark_adapter_resumed(&i2c_imx->adapter);
if (i2c_imx->slave) {
hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY);
hrtimer_restart(&i2c_imx->slave_timer);
}
return ret;
}
return 0;
}
static int __maybe_unused i2c_imx_resume_noirq(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
i2c_mark_adapter_resumed(&i2c_imx->adapter);
return 0;
}
static int i2c_imx_suspend(struct device *dev)
{
/*
@@ -1985,8 +2029,8 @@ static int i2c_imx_resume(struct device *dev)
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend_noirq,
i2c_imx_resume_noirq)
SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
};
+4 -1
View File
@@ -141,6 +141,7 @@ struct jz4780_i2c {
void __iomem *iomem;
int irq;
struct clk *clk;
unsigned long clk_rate_khz;
struct i2c_adapter adap;
const struct ingenic_i2c_config *cdata;
@@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
{
int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
int dev_clk_khz = i2c->clk_rate_khz;
int cnt_high = 0; /* HIGH period count of the SCL clock */
int cnt_low = 0; /* LOW period count of the SCL clock */
int cnt_period = 0; /* period count of the SCL clock */
@@ -796,6 +797,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->clk))
return PTR_ERR(i2c->clk);
i2c->clk_rate_khz = clk_get_rate(i2c->clk) / 1000;
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&clk_freq);
if (ret) {
+5 -5
View File
@@ -723,11 +723,6 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
if (i2c->irq < 0)
return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq");
clk = devm_clk_get_enabled(dev, "func");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
@@ -755,6 +750,11 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
init_completion(&i2c->complete);
ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
IRQF_NO_SUSPEND, dev_name(i2c->dev), i2c);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq");
platform_set_drvdata(pdev, i2c);
ret = i2c_add_numbered_adapter(&i2c->adapt);
+1 -17
View File
@@ -492,24 +492,8 @@ static int __maybe_unused cci_resume_runtime(struct device *dev)
return 0;
}
static int __maybe_unused cci_suspend(struct device *dev)
{
if (!pm_runtime_suspended(dev))
return cci_suspend_runtime(dev);
return 0;
}
static int __maybe_unused cci_resume(struct device *dev)
{
cci_resume_runtime(dev);
pm_request_autosuspend(dev);
return 0;
}
static const struct dev_pm_ops qcom_cci_pm = {
SET_SYSTEM_SLEEP_PM_OPS(cci_suspend, cci_resume)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL)
};