i2c: qcom-geni: Isolate serial engine setup

Moving the serial engine setup to geni_i2c_init() API for a cleaner
probe function and utilizes the PM runtime API to control resources
instead of direct clock-related APIs for better resource management.

Enables reusability of the serial engine initialization like
hibernation and deep sleep features where hardware context is lost.

Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
Acked-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Mukesh Kumar Savaliya <mukesh.savaliya@oss.qualcomm.com>
Tested-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Link: https://lore.kernel.org/r/20260617-enable-i2c-on-sa8255p-v7-2-ad736dbeab57@oss.qualcomm.com
This commit is contained in:
Praveen Talari 2026-06-17 10:20:16 +05:30 committed by Andi Shyti
parent fd359c0272
commit d8d3bb127a
No known key found for this signature in database
GPG Key ID: DA78056626D32D6E

View File

@ -990,10 +990,77 @@ static int setup_gpi_dma(struct geni_i2c_dev *gi2c)
return ret; return ret;
} }
static int geni_i2c_init(struct geni_i2c_dev *gi2c)
{
const struct geni_i2c_desc *desc = NULL;
u32 proto, tx_depth;
bool fifo_disable;
int ret;
ret = pm_runtime_resume_and_get(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "error turning on device :%d\n", ret);
return ret;
}
proto = geni_se_read_proto(&gi2c->se);
if (proto == GENI_SE_INVALID_PROTO) {
ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
if (ret) {
dev_err_probe(gi2c->se.dev, ret, "i2c firmware load failed ret: %d\n", ret);
goto err;
}
} else if (proto != GENI_SE_I2C) {
ret = dev_err_probe(gi2c->se.dev, -ENXIO, "Invalid proto %d\n", proto);
goto err;
}
desc = device_get_match_data(gi2c->se.dev);
if (desc && desc->no_dma_support) {
fifo_disable = false;
gi2c->no_dma = true;
} else {
fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
}
if (fifo_disable) {
/* FIFO is disabled, so we can only use GPI DMA */
gi2c->gpi_mode = true;
ret = setup_gpi_dma(gi2c);
if (ret)
goto err;
dev_dbg(gi2c->se.dev, "Using GPI DMA mode for I2C\n");
} else {
gi2c->gpi_mode = false;
tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
/* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
if (!tx_depth && desc)
tx_depth = desc->tx_fifo_depth;
if (!tx_depth) {
ret = dev_err_probe(gi2c->se.dev, -EINVAL,
"Invalid TX FIFO depth\n");
goto err;
}
gi2c->tx_wm = tx_depth - 1;
geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
PACKING_BYTES_PW, true, true, true);
dev_dbg(gi2c->se.dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
}
err:
pm_runtime_put(gi2c->se.dev);
return ret;
}
static int geni_i2c_probe(struct platform_device *pdev) static int geni_i2c_probe(struct platform_device *pdev)
{ {
struct geni_i2c_dev *gi2c; struct geni_i2c_dev *gi2c;
u32 proto, tx_depth, fifo_disable;
int ret; int ret;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct geni_i2c_desc *desc = NULL; const struct geni_i2c_desc *desc = NULL;
@ -1073,101 +1140,26 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(gi2c->core_clk);
if (ret)
return ret;
ret = geni_se_resources_on(&gi2c->se);
if (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_INVALID_PROTO) {
ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
if (ret) {
dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret);
goto err_resources;
}
} else if (proto != GENI_SE_I2C) {
ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto);
goto err_resources;
}
if (desc && desc->no_dma_support) {
fifo_disable = false;
gi2c->no_dma = true;
} else {
fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
}
if (fifo_disable) {
/* FIFO is disabled, so we can only use GPI DMA */
gi2c->gpi_mode = true;
ret = setup_gpi_dma(gi2c);
if (ret)
goto err_resources;
dev_dbg(dev, "Using GPI DMA mode for I2C\n");
} else {
gi2c->gpi_mode = false;
tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
/* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
if (!tx_depth && desc)
tx_depth = desc->tx_fifo_depth;
if (!tx_depth) {
ret = dev_err_probe(dev, -EINVAL,
"Invalid TX FIFO depth\n");
goto err_resources;
}
gi2c->tx_wm = tx_depth - 1;
geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
PACKING_BYTES_PW, true, true, true);
dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
}
clk_disable_unprepare(gi2c->core_clk);
ret = geni_se_resources_off(&gi2c->se);
if (ret) {
dev_err_probe(dev, ret, "Error turning off resources\n");
goto err_dma;
}
ret = geni_icc_disable(&gi2c->se);
if (ret)
goto err_dma;
pm_runtime_set_suspended(gi2c->se.dev); pm_runtime_set_suspended(gi2c->se.dev);
pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(gi2c->se.dev); pm_runtime_use_autosuspend(gi2c->se.dev);
pm_runtime_enable(gi2c->se.dev); pm_runtime_enable(gi2c->se.dev);
ret = geni_i2c_init(gi2c);
if (ret < 0) {
pm_runtime_disable(gi2c->se.dev);
return ret;
}
ret = i2c_add_adapter(&gi2c->adap); ret = i2c_add_adapter(&gi2c->adap);
if (ret) { if (ret) {
dev_err_probe(dev, ret, "Error adding i2c adapter\n"); dev_err_probe(dev, ret, "Error adding i2c adapter\n");
pm_runtime_disable(gi2c->se.dev); pm_runtime_disable(gi2c->se.dev);
goto err_dma; return ret;
} }
dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); dev_dbg(dev, "Geni-I2C adaptor successfully added\n");
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; return ret;
} }