mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 10:31:33 -04:00
Merge tag 'i2c-fixes-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux
Pull i2c fixes from Andi Shyti: "Fixes mainly for teardown and resource handling, runtime PM and hardware-specific controller issues: - fix debugfs use-after-free when removing the adapter - designware: apply interrupt mask quirk for HJMC3001 - imx-lpi2c: avoid target accesses on master-only controllers - mux: release channel node when adapter registration fails - qcom-cci: fix autosuspend and runtime PM cleanup on removal - qcom-geni: fix timing parameters for 32 MHz clock" * tag 'i2c-fixes-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux: i2c: core: fix debugfs UAF on adapter removal i2c: imx-lpi2c: avoid accessing target registers on master-only controllers i2c: qcom-cci: fix autosuspend cleanup i2c: designware: Enable interrupt mask workaround for HJMC3001 i2c: qcom-geni: update frequency table to fix timing parameters i2c: mux: Fix channel node leak on adapter add failure
This commit is contained in:
@@ -272,7 +272,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
||||
{ "HISI02A1", 0 },
|
||||
{ "HISI02A2", 0 },
|
||||
{ "HISI02A3", 0 },
|
||||
{ "HJMC3001", 0 },
|
||||
{ "HJMC3001", ACCESS_INTR_MASK },
|
||||
{ "HYGO0010", ACCESS_INTR_MASK },
|
||||
{ "INT33C2", 0 },
|
||||
{ "INT33C3", 0 },
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#define DRIVER_NAME "imx-lpi2c"
|
||||
|
||||
#define LPI2C_VERID 0x00 /* i2c version ID */
|
||||
#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
|
||||
#define LPI2C_MCR 0x10 /* i2c contrl register */
|
||||
#define LPI2C_MSR 0x14 /* i2c status register */
|
||||
@@ -136,6 +137,9 @@
|
||||
#define I2C_PM_LONG_TIMEOUT_MS 1000 /* Avoid dead lock caused by big clock prepare lock */
|
||||
#define I2C_DMA_THRESHOLD 8 /* bytes */
|
||||
|
||||
/* Bit 0 indicates the presence of the target feature */
|
||||
#define VERID_FEATURE_TARGET_PRESENT BIT(0)
|
||||
|
||||
enum lpi2c_imx_mode {
|
||||
STANDARD, /* 100+Kbps */
|
||||
FAST, /* 400+Kbps */
|
||||
@@ -194,6 +198,7 @@ struct lpi2c_imx_struct {
|
||||
bool can_use_dma;
|
||||
struct lpi2c_imx_dma *dma;
|
||||
struct i2c_client *target;
|
||||
bool target_supported;
|
||||
int irq;
|
||||
const struct imx_lpi2c_hwdata *hwdata;
|
||||
};
|
||||
@@ -1330,6 +1335,10 @@ static int lpi2c_imx_register_target(struct i2c_client *client)
|
||||
struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter);
|
||||
int ret;
|
||||
|
||||
/* Reject target-mode registration on controllers that don't support it. */
|
||||
if (!lpi2c_imx->target_supported)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (lpi2c_imx->target)
|
||||
return -EBUSY;
|
||||
|
||||
@@ -1546,13 +1555,23 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/*
|
||||
* Reset all internal controller registers of both Master and Target
|
||||
* to avoid effects of previous status.
|
||||
* Reset all internal controller registers to avoid effects of any
|
||||
* state left over from a previous stage (e.g. the bootloader).
|
||||
*
|
||||
* The Master block (MCR) is present on every controller, so reset it
|
||||
* unconditionally. VERID shows whether the target feature is supported.
|
||||
* Do not touch the Target block (SCR) on a master-only controller to
|
||||
* avoid an asynchronous SError.
|
||||
*/
|
||||
writel(MCR_RST, lpi2c_imx->base + LPI2C_MCR);
|
||||
writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
|
||||
writel(0, lpi2c_imx->base + LPI2C_MCR);
|
||||
writel(0, lpi2c_imx->base + LPI2C_SCR);
|
||||
|
||||
lpi2c_imx->target_supported = !!(readl(lpi2c_imx->base + LPI2C_VERID) &
|
||||
VERID_FEATURE_TARGET_PRESENT);
|
||||
if (lpi2c_imx->target_supported) {
|
||||
writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR);
|
||||
writel(0, lpi2c_imx->base + LPI2C_SCR);
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
pdev->name, lpi2c_imx);
|
||||
|
||||
@@ -595,9 +595,11 @@ static int cci_probe(struct platform_device *pdev)
|
||||
goto disable_clocks;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
ret = devm_pm_runtime_set_active_enabled(dev);
|
||||
if (ret)
|
||||
goto disable_clocks;
|
||||
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
for (i = 0; i < cci->data->num_masters; i++) {
|
||||
if (!cci->master[i].cci)
|
||||
@@ -613,8 +615,6 @@ static int cci_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
error_i2c:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_dont_use_autosuspend(dev);
|
||||
|
||||
for (--i ; i >= 0; i--) {
|
||||
if (cci->master[i].cci) {
|
||||
@@ -640,9 +640,6 @@ static void cci_remove(struct platform_device *pdev)
|
||||
cci_halt(cci, i);
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct cci_data cci_v1_data = {
|
||||
|
||||
@@ -188,8 +188,8 @@ static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
|
||||
|
||||
/* source_clock = 32 MHz */
|
||||
static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = {
|
||||
{ I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 38 },
|
||||
{ I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 },
|
||||
{ I2C_MAX_STANDARD_MODE_FREQ, 12, 9, 10, 26 },
|
||||
{ I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 },
|
||||
{ I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 5, 15 },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1816,6 +1816,12 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This drains any in-flight writers, so all
|
||||
* clients will be caught by i2c_deregister_clients().
|
||||
*/
|
||||
device_remove_file(&adap->dev, &dev_attr_new_device);
|
||||
|
||||
i2c_acpi_remove_space_handler(adap);
|
||||
|
||||
i2c_deregister_clients(adap);
|
||||
|
||||
@@ -408,6 +408,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
|
||||
return 0;
|
||||
|
||||
err_free_priv:
|
||||
of_node_put(priv->adap.dev.of_node);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user