mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
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:
parent
fd359c0272
commit
d8d3bb127a
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user