diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-qcom-geni.c')
-rw-r--r-- | drivers/i2c/busses/i2c-qcom-geni.c | 111 |
1 files changed, 65 insertions, 46 deletions
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index da94df466e83..7bbd478171e0 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -16,6 +16,7 @@ #include <linux/pm_runtime.h> #include <linux/soc/qcom/geni-se.h> #include <linux/spinlock.h> +#include <linux/units.h> #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -146,22 +147,36 @@ struct geni_i2c_clk_fld { * clk_freq_out = t / t_cycle * source_clock = 19.2 MHz */ -static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { +static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = { {KHZ(100), 7, 10, 11, 26}, {KHZ(400), 2, 5, 12, 24}, {KHZ(1000), 1, 3, 9, 18}, + {}, +}; + +/* source_clock = 32 MHz */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { + {KHZ(100), 8, 14, 18, 40}, + {KHZ(400), 4, 3, 11, 20}, + {KHZ(1000), 2, 3, 6, 15}, + {}, }; static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) { - int i; - const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + const struct geni_i2c_clk_fld *itr; - for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + if (clk_get_rate(gi2c->se.clk) == 32 * HZ_PER_MHZ) + itr = geni_i2c_clk_map_32mhz; + else + itr = geni_i2c_clk_map_19p2mhz; + + while (itr->clk_freq_out != 0) { if (itr->clk_freq_out == gi2c->clk_freq_out) { gi2c->clk_fld = itr; return 0; } + itr++; } return -EINVAL; } @@ -586,7 +601,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i { struct dma_slave_config config = {}; struct gpi_i2c_config peripheral = {}; - int i, ret = 0, timeout; + int i, ret = 0; + unsigned long time_left; dma_addr_t tx_addr, rx_addr; void *tx_buf = NULL, *rx_buf = NULL; const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; @@ -629,12 +645,9 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i dma_async_issue_pending(gi2c->tx_c); - timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!timeout) { - dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n", - gi2c->cur->flags, gi2c->cur->addr); + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) gi2c->err = -ETIMEDOUT; - } if (gi2c->err) { ret = gi2c->err; @@ -723,7 +736,7 @@ static const struct i2c_algorithm geni_i2c_algo = { static const struct acpi_device_id geni_i2c_acpi_match[] = { { "QCOM0220"}, { "QCOM0411" }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); #endif @@ -810,25 +823,22 @@ static int geni_i2c_probe(struct platform_device *pdev) return gi2c->irq; ret = geni_i2c_clk_map_idx(gi2c); - if (ret) { - dev_err(dev, "Invalid clk frequency %d Hz: %d\n", - gi2c->clk_freq_out, ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Invalid clk frequency %d Hz\n", + gi2c->clk_freq_out); gi2c->adap.algo = &geni_i2c_algo; init_completion(&gi2c->done); spin_lock_init(&gi2c->lock); platform_set_drvdata(pdev, gi2c); - ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0, + + /* Keep interrupts disabled initially to allow for low-power modes */ + ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); - if (ret) { - dev_err(dev, "Request_irq failed:%d: err:%d\n", - gi2c->irq, ret); - return ret; - } - /* Disable the interrupt so that the system can enter low-power mode */ - disable_irq(gi2c->irq); + if (ret) + return dev_err_probe(dev, ret, + "Request_irq failed: %d\n", gi2c->irq); + i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = dev; gi2c->adap.dev.of_node = dev->of_node; @@ -857,16 +867,13 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = geni_se_resources_on(&gi2c->se); if (ret) { - dev_err(dev, "Error turning on resources %d\n", ret); - clk_disable_unprepare(gi2c->core_clk); - return ret; + dev_err_probe(dev, ret, "Error turning on resources\n"); + goto err_clk; } proto = geni_se_read_proto(&gi2c->se); if (proto != GENI_SE_I2C) { - dev_err(dev, "Invalid proto %d\n", proto); - geni_se_resources_off(&gi2c->se); - clk_disable_unprepare(gi2c->core_clk); - return -ENXIO; + ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto); + goto err_resources; } if (desc && desc->no_dma_support) @@ -878,11 +885,8 @@ static int geni_i2c_probe(struct platform_device *pdev) /* FIFO is disabled, so we can only use GPI DMA */ gi2c->gpi_mode = true; ret = setup_gpi_dma(gi2c); - if (ret) { - geni_se_resources_off(&gi2c->se); - clk_disable_unprepare(gi2c->core_clk); - return dev_err_probe(dev, ret, "Failed to setup GPI DMA mode\n"); - } + if (ret) + goto err_resources; dev_dbg(dev, "Using GPI DMA mode for I2C\n"); } else { @@ -894,10 +898,9 @@ static int geni_i2c_probe(struct platform_device *pdev) tx_depth = desc->tx_fifo_depth; if (!tx_depth) { - dev_err(dev, "Invalid TX FIFO depth\n"); - geni_se_resources_off(&gi2c->se); - clk_disable_unprepare(gi2c->core_clk); - return -EINVAL; + ret = dev_err_probe(dev, -EINVAL, + "Invalid TX FIFO depth\n"); + goto err_resources; } gi2c->tx_wm = tx_depth - 1; @@ -911,7 +914,7 @@ static int geni_i2c_probe(struct platform_device *pdev) clk_disable_unprepare(gi2c->core_clk); ret = geni_se_resources_off(&gi2c->se); if (ret) { - dev_err(dev, "Error turning off resources %d\n", ret); + dev_err_probe(dev, ret, "Error turning off resources\n"); goto err_dma; } @@ -927,17 +930,25 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&gi2c->adap); if (ret) { - dev_err(dev, "Error adding i2c adapter %d\n", ret); + dev_err_probe(dev, ret, "Error adding i2c adapter\n"); pm_runtime_disable(gi2c->se.dev); goto err_dma; } dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); - return 0; + return ret; + +err_resources: + geni_se_resources_off(&gi2c->se); +err_clk: + clk_disable_unprepare(gi2c->core_clk); + + return ret; err_dma: release_gpi_dma(gi2c); + return ret; } @@ -989,15 +1000,23 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) ret = clk_prepare_enable(gi2c->core_clk); if (ret) - return ret; + goto out_icc_disable; ret = geni_se_resources_on(&gi2c->se); if (ret) - return ret; + goto out_clk_disable; enable_irq(gi2c->irq); gi2c->suspended = 0; + return 0; + +out_clk_disable: + clk_disable_unprepare(gi2c->core_clk); +out_icc_disable: + geni_icc_disable(&gi2c->se); + + return ret; } static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) @@ -1045,7 +1064,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); static struct platform_driver geni_i2c_driver = { .probe = geni_i2c_probe, - .remove_new = geni_i2c_remove, + .remove = geni_i2c_remove, .shutdown = geni_i2c_shutdown, .driver = { .name = "geni_i2c", |