[Patch V7] i2c: imx: add runtime pm support to improve the performance
In our former i2c driver, i2c clk is enabled and disabled in xfer function, which contributes to power saving. However, the clk enable process brings a busy wait delay until the core is stable. As a result, the performance is sacrificed. To weigh the power consumption and i2c bus performance, runtime pm is the good solution for it. The clk is enabled when a i2c transfer starts, and disabled after a specifically defined delay. Without the patch the test case (many eeprom reads) executes with approx: real 1m7.735s user 0m0.488s sys 0m20.040s With the patch the same test case (many eeprom reads) executes with approx: real 0m54.241s user 0m0.440s sys 0m5.920s Signed-off-by: Fugang Duan Signed-off-by: Gao Pan [wsa: fixed some indentation] Signed-off-by: Wolfram Sang --- V2: As Uwe Kleine-König's suggestion, the version do below changes: -call clk_prepare_enable in probe to avoid never enabling clock if CONFIG_PM is disabled -enable clock before request IRQ in probe -remove the pm staff in i2c_imx_isr V3: -pm_runtime_get_sync returns < 0 as error V4: -add pm_runtime_set_active before pm_runtime_enable -replace pm_runtime_put_autosuspend with pm_runtime_autosuspend in probe -add error disposal when i2c_add_numbered_adapter fails V5: -clean up and disable runtime PM when i2c_add_numbered_adapter fails -use pm_runtime_get and pm_runtime_put_autosuspend in probe V6: -disable the clock manually and set the state to suspended explicitly with pm_runtime_set_suspended V7: -manually disabling the clock and use pm_runtime_put_noidle in the remove callback drivers/i2c/busses/i2c-imx.c | 90 ++-- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 785aa67..d7c823b 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -53,6 +53,7 @@ #include #include #include +#include /** Defines ***/ @@ -118,6 +119,8 @@ #define I2CR_IEN_OPCODE_0 0x0 #define I2CR_IEN_OPCODE_1 I2CR_IEN +#define I2C_PM_TIMEOUT 10 /* ms */ + /** Variables ** ***/ @@ -520,9 +523,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) i2c_imx_set_clk(i2c_imx); - result = clk_prepare_enable(i2c_imx->clk); - if (result) - return result; imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); /* Enable I2C controller */ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); @@ -575,7 +575,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) /* Disable I2C controller */ temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - clk_disable_unprepare(i2c_imx->clk); } static irqreturn_t i2c_imx_isr(int irq, void *dev_id) @@ -894,6 +893,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); + if (result < 0) + goto out; + /* Start I2C transfer */ result = i2c_imx_start(i2c_imx); if (result) @@ -950,6 +953,10 @@ fail0: /* Stop I2C transfer */ i2c_imx_stop(i2c_imx); +out: + pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); + pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); + dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, (result < 0) ? "error" : "success msg", (result < 0) ? result : num); @@ -1020,9 +1027,10 @@ static int i2c_imx_probe(struct platform_device *pdev) ret = clk_prepare_enable(i2c_imx->clk); if (ret) { - dev_err(&pdev->dev, "can't enable I2C clock\n"); + dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret); return ret; } + /* Request IRQ */ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, pdev->name, i2c_imx); @@ -1037,6 +1045,18 @@ static int i2c_imx_probe(struct platform_device *pdev) /* Set up adapter data */ i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); + /* Set up platform driver data */ + platform_set_drvdata(pdev, i2c_imx); + + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + goto rpm_disable; + /*
RE: [Patch V6] i2c: imx: add runtime pm support to improve the performance
> -Original Message- > From: Heiner Kallweit [mailto:hkallwe...@gmail.com] > Sent: Monday, August 31, 2015 2:14 PM > To: Gao Pan-B54642; w...@the-dreams.de > Cc: linux-i2c@vger.kernel.org; Li Frank-B20596; Duan Fugang-B38611; > u.kleine-koe...@pengutronix.de; ker...@pengutronix.de > Subject: Re: [Patch V6] i2c: imx: add runtime pm support to improve the > performance > > Am 28.08.2015 um 08:30 schrieb Gao Pan: > > In our former i2c driver, i2c clk is enabled and disabled in xfer > > function, which contributes to power saving. However, the clk enable > > process brings a busy wait delay until the core is stable. As a > > result, the performance is sacrificed. > > > > To weigh the power consumption and i2c bus performance, runtime pm is > > the good solution for it. The clk is enabled when a i2c transfer > > starts, and disabled after a specifically defined delay. > > > > Without the patch the test case (many eeprom reads) executes with > approx: > > real 1m7.735s > > user 0m0.488s > > sys 0m20.040s > > > > With the patch the same test case (many eeprom reads) executes with > approx: > > real 0m54.241s > > user 0m0.440s > > sys 0m5.920s > > > > Signed-off-by: Fugang Duan > > Signed-off-by: Gao Pan > > [wsa: fixed some indentation] > > Signed-off-by: Wolfram Sang > > --- > > V2: > > As Uwe Kleine-König's suggestion, the version do below changes: > > -call clk_prepare_enable in probe to avoid never enabling clock > > if CONFIG_PM is disabled > > -enable clock before request IRQ in probe -remove the pm staff in > > i2c_imx_isr > > > > V3: > > -pm_runtime_get_sync returns < 0 as error > > > > V4: > > -add pm_runtime_set_active before pm_runtime_enable -replace > > pm_runtime_put_autosuspend with pm_runtime_autosuspend > > in probe > > -add error disposal when i2c_add_numbered_adapter fails > > > > V5: > > -clean up and disable runtime PM when i2c_add_numbered_adapter fails > > -use pm_runtime_get and pm_runtime_put_autosuspend in probe > > > > V6: > > -disable the clock manually and set the state to suspended explicitly > with > > pm_runtime_set_suspended > > > > drivers/i2c/busses/i2c-imx.c | 88 > > ++-- > > 1 file changed, 76 insertions(+), 12 deletions(-) > > > > diff --git a/drivers/i2c/busses/i2c-imx.c > > b/drivers/i2c/busses/i2c-imx.c index 785aa67..ac85e5c 100644 > > --- a/drivers/i2c/busses/i2c-imx.c > > +++ b/drivers/i2c/busses/i2c-imx.c > > @@ -53,6 +53,7 @@ > > #include > > #include > > #include > > +#include > > > > /** Defines > > > > > > ** > > */ > > @@ -118,6 +119,8 @@ > > #define I2CR_IEN_OPCODE_0 0x0 > > #define I2CR_IEN_OPCODE_1 I2CR_IEN > > > > +#define I2C_PM_TIMEOUT 10 /* ms */ > > + > > /** Variables > > ** > > > > ** > > */ > > > > @@ -520,9 +523,6 @@ static int i2c_imx_start(struct imx_i2c_struct > > *i2c_imx) > > > > i2c_imx_set_clk(i2c_imx); > > > > - result = clk_prepare_enable(i2c_imx->clk); > > - if (result) > > - return result; > > imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); > > /* Enable I2C controller */ > > imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, > > IMX_I2C_I2SR); @@ -575,7 +575,6 @@ static void i2c_imx_stop(struct > imx_i2c_struct *i2c_imx) > > /* Disable I2C controller */ > > temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, > > imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); > > - clk_disable_unprepare(i2c_imx->clk); > > } > > > > static irqreturn_t i2c_imx_isr(int irq, void *dev_id) @@ -894,6 > > +893,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, > > > > dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); > > > > + result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); > > + if (result < 0) > > + goto out; > > + > > /* Start I2C transfer */ > > result = i2c_imx_start(i2c_imx); > > if (result) > > @@ -950,6 +953,10 @@ fail0: > > /* Stop I2C transfer */ > > i2c_imx_stop(i2c_imx); > > > > +out: > > + pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); > > + pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); > > + > > dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, > > (result < 0) ? "error" : "success msg", > > (result < 0) ? result : num); > > @@ -1020,9 +1027,10 @@ static int i2c_imx_probe(struct platform_device > > *pdev) > > > > ret = clk_prepare_enable(i2c_imx->clk); > > if (ret) { > > - dev_err(&pdev->dev, "can't enable I2C clock\n"); > > + dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret); > > return ret; > > } > > + > > /* Request I
[PATCH 2/6] i2c: designware: Disable interrupts before requesting PCI device interrupt
Device must not generate interrupts before registering the interrupt handler so move i2c_dw_disable_int() before requesting it. There are no known issues with this. The code has been here since commit fe20ff5c7e9c ("i2c-designware: Add support for Designware core behind PCI devices."). Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index e477dddcdae5..d9e8937f062f 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -260,6 +260,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci"); + i2c_dw_disable_int(dev); r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev); if (r) { @@ -267,7 +268,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, return r; } - i2c_dw_disable_int(dev); r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/6] i2c: designware: Make dw_readl() and dw_writel() static
dw_readl() and dw_writel() are not used outside of i2c-designware-core and they are not exported so make them static and remove their forward declaration. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.c | 4 ++-- drivers/i2c/busses/i2c-designware-core.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index c9e93a76a455..52272a01c679 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -165,7 +165,7 @@ static char *abort_sources[] = { "lost arbitration", }; -u32 dw_readl(struct dw_i2c_dev *dev, int offset) +static u32 dw_readl(struct dw_i2c_dev *dev, int offset) { u32 value; @@ -181,7 +181,7 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset) return value; } -void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) +static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) { if (dev->accessor_flags & ACCESS_SWAP) b = swab32(b); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 10c79038834d..0e73b8672402 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -112,8 +112,6 @@ struct dw_i2c_dev { #define ACCESS_SWAP0x0001 #define ACCESS_16BIT 0x0002 -extern u32 dw_readl(struct dw_i2c_dev *dev, int offset); -extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); extern int i2c_dw_init(struct dw_i2c_dev *dev); extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/6] i2c: designware: Move common probe code into i2c_dw_probe()
There is some code duplication in i2c-designware-platdrv and i2c-designware-pcidrv probe functions. What is even worse that duplication requires i2c_dw_xfer(), i2c_dw_func() and i2c_dw_isr() i2c-designware-core functions to be exported. Therefore move common code into new i2c_dw_probe() and make functions above local to i2c-designware-core. While merging the code patch does following functional changes: - I2C Adapter name will be "i2c-designware". Previously adapter name was "Synopsys DesignWare I2C adapter" for platform and ACPI devices and "i2c-designware-pci" for PCI devices. - Interrupt name too will be "i2c-designware". Previous it was platform device name, ACPI device name or "i2c-designware-pci". - Error code from devm_request_irq() and i2c_add_numbered_adapter() will be printed in case of error. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.c| 48 + drivers/i2c/busses/i2c-designware-core.h| 5 +-- drivers/i2c/busses/i2c-designware-pcidrv.c | 30 ++ drivers/i2c/busses/i2c-designware-platdrv.c | 28 ++--- 4 files changed, 48 insertions(+), 63 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 52272a01c679..501c8ac0cf14 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -618,7 +618,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) /* * Prepare controller for a transaction and call i2c_dw_xfer_msg */ -int +static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); @@ -702,14 +702,17 @@ done_nolock: return ret; } -EXPORT_SYMBOL_GPL(i2c_dw_xfer); -u32 i2c_dw_func(struct i2c_adapter *adap) +static u32 i2c_dw_func(struct i2c_adapter *adap) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); return dev->functionality; } -EXPORT_SYMBOL_GPL(i2c_dw_func); + +static struct i2c_algorithm i2c_dw_algo = { + .master_xfer= i2c_dw_xfer, + .functionality = i2c_dw_func, +}; static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { @@ -770,7 +773,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) * Interrupt service routine. This gets called whenever an I2C interrupt * occurs. */ -irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; u32 stat, enabled; @@ -813,7 +816,6 @@ tx_aborted: return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(i2c_dw_isr); void i2c_dw_disable(struct dw_i2c_dev *dev) { @@ -838,5 +840,39 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) } EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); +int i2c_dw_probe(struct dw_i2c_dev *dev) +{ + struct i2c_adapter *adap = &dev->adapter; + int r; + + init_completion(&dev->cmd_complete); + mutex_init(&dev->lock); + + r = i2c_dw_init(dev); + if (r) + return r; + + snprintf(adap->name, sizeof(adap->name), "i2c-designware"); + adap->algo = &i2c_dw_algo; + adap->dev.parent = dev->dev; + i2c_set_adapdata(adap, dev); + + i2c_dw_disable_int(dev); + r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED, +adap->name, dev); + if (r) { + dev_err(dev->dev, "failure requesting irq %i: %d\n", + dev->irq, r); + return r; + } + + r = i2c_add_numbered_adapter(adap); + if (r) + dev_err(dev->dev, "failure adding adapter: %d\n", r); + + return r; +} +EXPORT_SYMBOL_GPL(i2c_dw_probe); + MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 0e73b8672402..1d50898e7b24 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -113,13 +113,10 @@ struct dw_i2c_dev { #define ACCESS_16BIT 0x0002 extern int i2c_dw_init(struct dw_i2c_dev *dev); -extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - int num); -extern u32 i2c_dw_func(struct i2c_adapter *adap); -extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id); extern void i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); +extern int i2c_dw_probe(struct dw_i2c_dev *dev); #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index d9e8937f062f..169be1e26241 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++
[PATCH 5/6] i2c: designware: Rename platform driver probe and PM functions
Make it easier to distinguish between i2c-designware-platdrv and i2c-designware-core functions and to be consistent with i2c-designware-pcidrv. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-platdrv.c | 24 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 3dd2de31a2f8..17167cd4812d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -133,7 +133,7 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { } #endif -static int dw_i2c_probe(struct platform_device *pdev) +static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; @@ -271,7 +271,7 @@ static int dw_i2c_probe(struct platform_device *pdev) return 0; } -static int dw_i2c_remove(struct platform_device *pdev) +static int dw_i2c_plat_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); @@ -300,12 +300,12 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #endif #ifdef CONFIG_PM_SLEEP -static int dw_i2c_prepare(struct device *dev) +static int dw_i2c_plat_prepare(struct device *dev) { return pm_runtime_suspended(dev); } -static void dw_i2c_complete(struct device *dev) +static void dw_i2c_plat_complete(struct device *dev) { if (dev->power.direct_complete) pm_request_resume(dev); @@ -316,7 +316,7 @@ static void dw_i2c_complete(struct device *dev) #endif #ifdef CONFIG_PM -static int dw_i2c_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); @@ -327,7 +327,7 @@ static int dw_i2c_suspend(struct device *dev) return 0; } -static int dw_i2c_resume(struct device *dev) +static int dw_i2c_plat_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); @@ -341,10 +341,10 @@ static int dw_i2c_resume(struct device *dev) } static const struct dev_pm_ops dw_i2c_dev_pm_ops = { - .prepare = dw_i2c_prepare, - .complete = dw_i2c_complete, - SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume) - SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL) + .prepare = dw_i2c_plat_prepare, + .complete = dw_i2c_plat_complete, + SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL) }; #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) @@ -356,8 +356,8 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = { MODULE_ALIAS("platform:i2c_designware"); static struct platform_driver dw_i2c_driver = { - .probe = dw_i2c_probe, - .remove = dw_i2c_remove, + .probe = dw_i2c_plat_probe, + .remove = dw_i2c_plat_remove, .driver = { .name = "i2c_designware", .of_match_table = of_match_ptr(dw_i2c_of_match), -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/6] i2c: designware: Remove unused functions
i2c_dw_is_enabled() became unused by the commit be58eda775c8 ("i2c: designware-pci: Cleanup driver power management") and i2c_dw_enable() by the commit 3a48d1c08fe0 ("i2c: prevent spurious interrupt on Designware controllers"). Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.c | 13 - drivers/i2c/busses/i2c-designware-core.h | 2 -- 2 files changed, 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index dec0af7d0471..c9e93a76a455 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -815,19 +815,6 @@ tx_aborted: } EXPORT_SYMBOL_GPL(i2c_dw_isr); -void i2c_dw_enable(struct dw_i2c_dev *dev) -{ - /* Enable the adapter */ - __i2c_dw_enable(dev, true); -} -EXPORT_SYMBOL_GPL(i2c_dw_enable); - -u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) -{ - return dw_readl(dev, DW_IC_ENABLE); -} -EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); - void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index f44aeeeb91c6..10c79038834d 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -119,8 +119,6 @@ extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); extern u32 i2c_dw_func(struct i2c_adapter *adap); extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id); -extern void i2c_dw_enable(struct dw_i2c_dev *dev); -extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev); extern void i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/6] i2c: designware: Code duplication removal and cleanups
It bothered to me to see "static struct i2c_algorithm i2c_dw_algo {}" defined twice both in i2c-designware-pcidrv.c and i2c-designware-platdrv.c and so many exported i2c-designware-core functions. It turned out some of them became unused or are local and there were also duplicated probe code that I moved to new common i2c_dw_probe(). Object sizes below before and after this set from CONFIG_X86_64=y build. textdata bss dec hex filename 64391096 075351d6f drivers/i2c/busses/i2c-designware-core.ko 51231588 1667271a47 drivers/i2c/busses/i2c-designware-pci.ko 52741096 16638618f2 drivers/i2c/busses/i2c-designware-platform.ko 168363780 32 2064850a8 (TOTALS) textdata bss dec hex filename 72251120 16836120a9 drivers/i2c/busses/i2c-designware-core.ko 42811524 0580516ad drivers/i2c/busses/i2c-designware-pci.ko 43371072 054091521 drivers/i2c/busses/i2c-designware-platform.ko 158433716 16 195754c77 (TOTALS) Jarkko Nikula (6): i2c: designware: Remove interrupt clearing from i2c_dw_pci_probe() i2c: designware: Disable interrupts before requesting PCI device interrupt i2c: designware: Remove unused functions i2c: designware: Make dw_readl() and dw_writel() static i2c: designware: Rename platform driver probe and PM functions i2c: designware: Move common probe code into i2c_dw_probe() drivers/i2c/busses/i2c-designware-core.c| 73 ++--- drivers/i2c/busses/i2c-designware-core.h| 10 +--- drivers/i2c/busses/i2c-designware-pcidrv.c | 31 ++-- drivers/i2c/busses/i2c-designware-platdrv.c | 52 ++-- 4 files changed, 63 insertions(+), 103 deletions(-) -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/6] i2c: designware: Remove interrupt clearing from i2c_dw_pci_probe()
There is no need to clear interrupts in i2c_dw_pci_probe() since only place where interrupts are unmasked is i2c_dw_xfer_init() and there interrupts are always cleared after commit 2a2d95e9d6d2 ("i2c: designware: always clear interrupts before enabling them"). This allows to cleanup the code and replace i2c_dw_clear_int() in i2c_dw_xfer_init() by direct register read as there are no other callers. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.c | 8 +--- drivers/i2c/busses/i2c-designware-core.h | 1 - drivers/i2c/busses/i2c-designware-pcidrv.c | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 7441cdc1b34a..dec0af7d0471 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -438,7 +438,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) __i2c_dw_enable(dev, true); /* Clear and enable interrupts */ - i2c_dw_clear_int(dev); + dw_readl(dev, DW_IC_CLR_INTR); dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); } @@ -839,12 +839,6 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) } EXPORT_SYMBOL_GPL(i2c_dw_disable); -void i2c_dw_clear_int(struct dw_i2c_dev *dev) -{ - dw_readl(dev, DW_IC_CLR_INTR); -} -EXPORT_SYMBOL_GPL(i2c_dw_clear_int); - void i2c_dw_disable_int(struct dw_i2c_dev *dev) { dw_writel(dev, 0, DW_IC_INTR_MASK); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9630222abf32..f44aeeeb91c6 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -122,7 +122,6 @@ extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id); extern void i2c_dw_enable(struct dw_i2c_dev *dev); extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev); extern void i2c_dw_disable(struct dw_i2c_dev *dev); -extern void i2c_dw_clear_int(struct dw_i2c_dev *dev); extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index df23e8c30e6f..e477dddcdae5 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -268,7 +268,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, } i2c_dw_disable_int(dev); - i2c_dw_clear_int(dev); r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Do you need a loan?
We offer private, commercial and personal loans with very low annualinterest rates as low as 2% in one year to 50 years repayment period anywhere in the world. We offer loans ranging from $5000 to $100 million. Our loans are well insured for maximum security is our priority. Are you losing sleep at night worrying how to get a legitimate loan lender? You bite your nails that fast? Instead of beating you, contact JM Financial Services Ltd now, specialists who help stop loans bad credit history to find a solution that victory is our mission. Applicants must fill out a loan application form below: FORM credit application loan applications Your full name * Your e-mail * Your phone * Your address * Your city * State / Province * Country * Fax* Date of birth * Do you have an account? * Have you applied before? * The loan amount is needed * The Loan Duration* The life expectancy * The purpose of the loan * Send me a scanned copy of your passport: * Creditor: Mr. Prakash Lass Dickson. Company: JM Financial Services Ltd. Copyright JM Financial Ltd. All rights reserved. -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] i2c: mux: reg: simplify register size checking
On Fri, Aug 21, 2015 at 03:26:23AM +, York Sun wrote: > Sorry for top posting, I am out and replying using web access. > > This patch looks OK. I cannot test it until earliest next Friday. Did you have the chance to test it? Thanks, Wolfram signature.asc Description: Digital signature
Re: [RESEND PATCH 1/7] i2c: core: Export I2C module alias information in dummy driver
> > The dummy driver is always loaded when the i2c core inits. > > > > Ok, I wondered if that was the case but I > was not sure so I posted it just in case. Check the source code, this part is pretty obvious... signature.asc Description: Digital signature
Re: [PATCH] i2c: muxes: fix leaked i2c adapter device node references
On Wed, Aug 26, 2015 at 11:59:33PM +0300, Vladimir Zapolskiy wrote: > Every call of of_parse_phandle() increments user count of found device > node, if OF_DYNAMIC is enabled. > > The change fixes all similar addressed cases in drivers/i2c. > > Signed-off-by: Vladimir Zapolskiy Applied to for-next, thanks! signature.asc Description: Digital signature
Re: [PATCH] i2c: mux: reg: simplify register size checking
On 08/31/2015 03:24 PM, Wolfram Sang wrote: > On Fri, Aug 21, 2015 at 03:26:23AM +, York Sun wrote: >> Sorry for top posting, I am out and replying using web access. >> >> This patch looks OK. I cannot test it until earliest next Friday. > > Did you have the chance to test it? > I am working on it. My hardware was replaced with a new version. I am running my driver now. Will try your patch and confirm. York -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] drivers: i2c: exynos5: irq spinlock rt-safe
On 2015-08-25 23:51, Thomas Gleixner wrote: > On Tue, 25 Aug 2015, Anders Roxell wrote: > > > The exynos5_i2c_message_start enables interrupts while holding the i2c > > lock which is sought by the irq handler. If an IRQ is received before > > this lock is released then a deadlock occurs. > > That's crap. The interrupt handler runs in an irq thread as RT forces > all normal interrupts to that. You are right, I will send a v2 with a better changelog. Cheers, Anders -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] i2c: mux: reg: simplify register size checking
On 08/20/2015 04:40 PM, Wolfram Sang wrote: > Checking was done at three different locations, just do it once and > properly at probing time. > > Signed-off-by: Wolfram Sang > Cc: York Sun > --- > > York Sun: Can you test this patch? I can only build test. Patch is OK. Verified on hardware with good and intentional bad values. Acked-by: York Sun -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RESEND PATCH 1/7] i2c: core: Export I2C module alias information in dummy driver
Hello Wolfram, On 08/31/2015 10:31 PM, Wolfram Sang wrote: > >>> The dummy driver is always loaded when the i2c core inits. >>> >> >> Ok, I wondered if that was the case but I >> was not sure so I posted it just in case. > > Check the source code, this part is pretty obvious... > Yes, sorry for missing that obvious detail... Best regards, -- Javier Martinez Canillas Open Source Group Samsung Research America -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RESEND PATCH 1/7] i2c: core: Export I2C module alias information in dummy driver
On Tue, Sep 01, 2015 at 12:30:22AM +0200, Javier Martinez Canillas wrote: > Hello Wolfram, > > On 08/31/2015 10:31 PM, Wolfram Sang wrote: > > > >>> The dummy driver is always loaded when the i2c core inits. > >>> > >> > >> Ok, I wondered if that was the case but I > >> was not sure so I posted it just in case. > > > > Check the source code, this part is pretty obvious... > > > > Yes, sorry for missing that obvious detail... No problem, now you know :) signature.asc Description: Digital signature
Re: [Patch V7] i2c: imx: add runtime pm support to improve the performance
Am 31.08.2015 um 09:32 schrieb Gao Pan: > In our former i2c driver, i2c clk is enabled and disabled in > xfer function, which contributes to power saving. However, > the clk enable process brings a busy wait delay until the core > is stable. As a result, the performance is sacrificed. > > To weigh the power consumption and i2c bus performance, runtime > pm is the good solution for it. The clk is enabled when a i2c > transfer starts, and disabled after a specifically defined delay. > > Without the patch the test case (many eeprom reads) executes with approx: > real 1m7.735s > user 0m0.488s > sys 0m20.040s > > With the patch the same test case (many eeprom reads) executes with approx: > real 0m54.241s > user 0m0.440s > sys 0m5.920s > > Signed-off-by: Fugang Duan > Signed-off-by: Gao Pan > [wsa: fixed some indentation] > Signed-off-by: Wolfram Sang > --- > V2: > As Uwe Kleine-König's suggestion, the version do below changes: > -call clk_prepare_enable in probe to avoid never enabling clock > if CONFIG_PM is disabled > -enable clock before request IRQ in probe > -remove the pm staff in i2c_imx_isr > > V3: > -pm_runtime_get_sync returns < 0 as error > > V4: > -add pm_runtime_set_active before pm_runtime_enable > -replace pm_runtime_put_autosuspend with pm_runtime_autosuspend > in probe > -add error disposal when i2c_add_numbered_adapter fails > > V5: > -clean up and disable runtime PM when i2c_add_numbered_adapter fails > -use pm_runtime_get and pm_runtime_put_autosuspend in probe > > V6: > -disable the clock manually and set the state to suspended explicitly with > pm_runtime_set_suspended > > V7: > -manually disabling the clock and use pm_runtime_put_noidle in the remove > callback > > drivers/i2c/busses/i2c-imx.c | 90 > ++-- > 1 file changed, 78 insertions(+), 12 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c > index 785aa67..d7c823b 100644 > --- a/drivers/i2c/busses/i2c-imx.c > +++ b/drivers/i2c/busses/i2c-imx.c > @@ -53,6 +53,7 @@ > #include > #include > #include > +#include > > /** Defines > > > ***/ > @@ -118,6 +119,8 @@ > #define I2CR_IEN_OPCODE_00x0 > #define I2CR_IEN_OPCODE_1I2CR_IEN > > +#define I2C_PM_TIMEOUT 10 /* ms */ > + > /** Variables > ** > > ***/ > > @@ -520,9 +523,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) > > i2c_imx_set_clk(i2c_imx); > > - result = clk_prepare_enable(i2c_imx->clk); > - if (result) > - return result; > imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); > /* Enable I2C controller */ > imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, > IMX_I2C_I2SR); > @@ -575,7 +575,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) > /* Disable I2C controller */ > temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, > imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); > - clk_disable_unprepare(i2c_imx->clk); > } > > static irqreturn_t i2c_imx_isr(int irq, void *dev_id) > @@ -894,6 +893,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, > > dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); > > + result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); > + if (result < 0) > + goto out; > + > /* Start I2C transfer */ > result = i2c_imx_start(i2c_imx); > if (result) > @@ -950,6 +953,10 @@ fail0: > /* Stop I2C transfer */ > i2c_imx_stop(i2c_imx); > > +out: > + pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); > + pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); > + > dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, > (result < 0) ? "error" : "success msg", > (result < 0) ? result : num); > @@ -1020,9 +1027,10 @@ static int i2c_imx_probe(struct platform_device *pdev) > > ret = clk_prepare_enable(i2c_imx->clk); > if (ret) { > - dev_err(&pdev->dev, "can't enable I2C clock\n"); > + dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret); > return ret; > } > + > /* Request IRQ */ > ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, > pdev->name, i2c_imx); > @@ -1037,6 +1045,18 @@ static int i2c_imx_probe(struct platform_device *pdev) > /* Set up adapter data */ > i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); > > + /* Set up platform driver data */ > + platform_set_drvdata(pdev, i2c_imx); > + > + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT)