#define CHUNK_DATA 256
#define I2C_PM_TIMEOUT 10 /* ms */
+#define I2C_PM_LONG_TIMEOUT_MS 1000 /* Avoid dead lock caused by big clock prepare lock */
#define I2C_DMA_THRESHOLD 8 /* bytes */
enum lpi2c_imx_mode {
FOUR_PIN_PP,
};
+struct imx_lpi2c_hwdata {
+ bool need_request_free_irq; /* Needed by irqsteer */
+ bool need_prepare_unprepare_clk; /* Needed by LPCG */
+};
+
struct lpi2c_imx_dma {
bool using_pio_mode;
u8 rx_cmd_buf_len;
bool can_use_dma;
struct lpi2c_imx_dma *dma;
struct i2c_client *target;
+ int irq;
+ const struct imx_lpi2c_hwdata *hwdata;
+};
+
+static const struct imx_lpi2c_hwdata imx7ulp_lpi2c_hwdata = {
+};
+
+static const struct imx_lpi2c_hwdata imx8qxp_lpi2c_hwdata = {
+ .need_request_free_irq = true,
+ .need_prepare_unprepare_clk = true,
+};
+
+static const struct imx_lpi2c_hwdata imx8qm_lpi2c_hwdata = {
+ .need_request_free_irq = true,
+ .need_prepare_unprepare_clk = true,
};
#define lpi2c_imx_read_msr_poll_timeout(atomic, val, cond) \
};
static const struct of_device_id lpi2c_imx_of_match[] = {
- { .compatible = "fsl,imx7ulp-lpi2c" },
+ { .compatible = "fsl,imx7ulp-lpi2c", .data = &imx7ulp_lpi2c_hwdata,},
+ { .compatible = "fsl,imx8qxp-lpi2c", .data = &imx8qxp_lpi2c_hwdata,},
+ { .compatible = "fsl,imx8qm-lpi2c", .data = &imx8qm_lpi2c_hwdata,},
{ }
};
MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
struct resource *res;
dma_addr_t phy_addr;
unsigned int temp;
- int irq, ret;
+ int ret;
lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
if (!lpi2c_imx)
return -ENOMEM;
+ lpi2c_imx->hwdata = of_device_get_match_data(&pdev->dev);
+ if (!lpi2c_imx->hwdata)
+ return -ENODEV;
+
lpi2c_imx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(lpi2c_imx->base))
return PTR_ERR(lpi2c_imx->base);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ lpi2c_imx->irq = platform_get_irq(pdev, 0);
+ if (lpi2c_imx->irq < 0)
+ return lpi2c_imx->irq;
lpi2c_imx->adapter.owner = THIS_MODULE;
lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
if (ret)
lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
- ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
+ ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
pdev->name, lpi2c_imx);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq);
+ return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq);
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
platform_set_drvdata(pdev, lpi2c_imx);
return dev_err_probe(&pdev->dev, -EINVAL,
"can't get I2C peripheral clock rate\n");
- pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ if (lpi2c_imx->hwdata->need_prepare_unprepare_clk)
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS);
+ else
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ bool need_prepare_unprepare_clk = lpi2c_imx->hwdata->need_prepare_unprepare_clk;
+ bool need_request_free_irq = lpi2c_imx->hwdata->need_request_free_irq;
+
+ if (need_request_free_irq)
+ devm_free_irq(dev, lpi2c_imx->irq, lpi2c_imx);
- clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ if (need_prepare_unprepare_clk)
+ clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ else
+ clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks);
pinctrl_pm_select_sleep_state(dev);
return 0;
static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ bool need_prepare_unprepare_clk = lpi2c_imx->hwdata->need_prepare_unprepare_clk;
+ bool need_request_free_irq = lpi2c_imx->hwdata->need_request_free_irq;
int ret;
pinctrl_pm_select_default_state(dev);
- ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
- if (ret) {
- dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
- return ret;
+ if (need_prepare_unprepare_clk) {
+ ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clock %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (need_request_free_irq) {
+ ret = devm_request_irq(dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
+ dev_name(dev), lpi2c_imx);
+ if (ret) {
+ dev_err(dev, "can't claim irq %d\n", lpi2c_imx->irq);
+ return ret;
+ }
}
return 0;