diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 873e901a23d7..bd70c6bae5dc 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -164,12 +164,12 @@ static irqreturn_t cci_isr(int irq, void *dev) } if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK)) { - reset = CCI_RESET_CMD_M0_MASK; + reset |= CCI_RESET_CMD_M0_MASK; ret = IRQ_HANDLED; } if (unlikely(val & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK)) { - reset = CCI_RESET_CMD_M1_MASK; + reset |= CCI_RESET_CMD_M1_MASK; ret = IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index ed6495ef811c..c4c6202ff15a 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -201,28 +201,31 @@ static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) { const struct geni_i2c_clk_fld *itr; - unsigned long res_freq; + unsigned long req_freq, res_freq; + int ret; /* - * Frequency counter tables are calibrated for a specific source - * clock frequency and are not valid for any multiple of it - * (e.g. 64 MHz, 128 MHz). - * Use exact=true and verify res_freq matches req_freq literally - * to reject harmonics: a 64 MHz clock that divides evenly to - * 32 MHz would pass exact matching but produce double the intended - * I2C frequency with these counter values. + * Use 32 MHz only if already selected, otherwise use 19.2 MHz. + * Preferring 32 MHz merely because DFS supports it breaks I2C + * transfers on X1E80100 CRD. */ - if (!geni_se_clk_freq_match(&gi2c->se, GENI_SE_CLK_32MHZ, - &gi2c->clk_idx, &res_freq, true) && - res_freq == GENI_SE_CLK_32MHZ) { + if (clk_get_rate(gi2c->se.clk) == GENI_SE_CLK_32MHZ) { + req_freq = GENI_SE_CLK_32MHZ; itr = geni_i2c_clk_map_32mhz; - } else if (!geni_se_clk_freq_match(&gi2c->se, GENI_SE_CLK_19P2MHZ, - &gi2c->clk_idx, &res_freq, true) && - res_freq == GENI_SE_CLK_19P2MHZ) { - itr = geni_i2c_clk_map_19p2mhz; } else { - dev_err(gi2c->se.dev, - "Unsupported SE source clock: must be exactly 32 MHz or 19.2 MHz\n"); + req_freq = GENI_SE_CLK_19P2MHZ; + itr = geni_i2c_clk_map_19p2mhz; + } + + ret = geni_se_clk_freq_match(&gi2c->se, req_freq, &gi2c->clk_idx, + &res_freq, true); + if (ret) + return dev_err_probe(gi2c->se.dev, ret, + "Failed to find SE source clock %lu Hz\n", + req_freq); + if (res_freq != req_freq) { + dev_err(gi2c->se.dev, "Unsupported SE source clock %lu Hz\n", + res_freq); return -EINVAL; } diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index d3dda7534b0a..c10b4fd9b553 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -116,7 +116,7 @@ static int wmt_i2c_probe(struct platform_device *pdev) if (err) return err; - i2c->clk = of_clk_get(np, 0); + i2c->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), "unable to request clock\n"); diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 5e397a7e63f6..ba560462d451 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -67,6 +67,7 @@ enum i2c_scl_freq { * @rx_pos: Position within current RX message * @endianness: big/little-endian byte order * @clk: Pointer to AXI4-lite input clock + * @irq: Interrupt number * @state: See STATE_ * @singlemaster: Indicates bus is single master * @dynamic: Mode of controller @@ -95,6 +96,7 @@ struct xiic_i2c { int rx_pos; enum xiic_endian endianness; struct clk *clk; + int irq; enum xilinx_i2c_state state; bool singlemaster; bool dynamic; @@ -1506,9 +1508,17 @@ static int xiic_i2c_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(dev, XIIC_PM_TIMEOUT); pm_runtime_use_autosuspend(dev); - ret = devm_pm_runtime_set_active_enabled(dev); - if (ret) + /* + * Enable runtime PM by hand: devm_pm_runtime_set_active_enabled() + * tears down in an order that races the devm-enabled clock release and + * makes clk_core_disable() WARN (see xiic_i2c_remove()). + */ + ret = pm_runtime_set_active(dev); + if (ret) { + pm_runtime_dont_use_autosuspend(dev); return ret; + } + pm_runtime_enable(dev); /* SCL frequency configuration */ i2c->input_clk = clk_get_rate(i2c->clk); @@ -1517,10 +1527,15 @@ static int xiic_i2c_probe(struct platform_device *pdev) if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ) i2c->i2c_clk = 0; - ret = devm_request_threaded_irq(dev, irq, NULL, xiic_process, - IRQF_ONESHOT, pdev->name, i2c); + /* + * Request the IRQ non-managed: later probe steps unwind manually via + * goto, so a devm handler could still be live after that teardown runs. + */ + i2c->irq = irq; + ret = request_threaded_irq(irq, NULL, xiic_process, IRQF_ONESHOT, + pdev->name, i2c); if (ret) - return ret; + goto err_pm_disable; i2c->singlemaster = device_property_read_bool(dev, "single-master"); @@ -1537,14 +1552,16 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c->endianness = BIG; ret = xiic_reinit(i2c); - if (ret) - return dev_err_probe(dev, ret, "Cannot xiic_reinit\n"); + if (ret) { + dev_err_probe(dev, ret, "Cannot xiic_reinit\n"); + goto err_free_irq; + } /* add i2c adapter to i2c tree */ ret = i2c_add_numbered_adapter(&i2c->adap); if (ret) { xiic_deinit(i2c); - return ret; + goto err_free_irq; } if (pdata) { @@ -1557,6 +1574,15 @@ static int xiic_i2c_probe(struct platform_device *pdev) res, irq, i2c->i2c_clk); return 0; + +err_free_irq: + free_irq(irq, i2c); +err_pm_disable: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); + + return ret; } static void xiic_i2c_remove(struct platform_device *pdev) @@ -1568,6 +1594,8 @@ static void xiic_i2c_remove(struct platform_device *pdev) /* remove adapter & data */ i2c_del_adapter(&i2c->adap); + free_irq(i2c->irq, i2c); + ret = pm_runtime_get_sync(dev); if (ret < 0) dev_warn(dev, "Failed to activate device for removal (%pe)\n", @@ -1575,7 +1603,10 @@ static void xiic_i2c_remove(struct platform_device *pdev) else xiic_deinit(i2c); - pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); } static const struct dev_pm_ops xiic_dev_pm_ops = {