mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'i2c/i2c-fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user