From 43df43e6ba139e6cd77ea31ca27efc67ea2df44b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 23 Aug 2017 16:46:12 +0300 Subject: i2c: designware: Don't set SCL timings and speed mode when in slave mode According to data sheet SCL timing parameters and DW_IC_CON SPEED mode bits are not used when operating in slave mode. Signed-off-by: Jarkko Nikula Tested-by: Luis Oliveira Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 11 ----- drivers/i2c/busses/i2c-designware-slave.c | 64 ----------------------------- 2 files changed, 75 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 58add69a441c..293f586d78d2 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -201,17 +201,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED; dev->mode = DW_IC_SLAVE; - - switch (dev->clk_freq) { - case 100000: - dev->slave_cfg |= DW_IC_CON_SPEED_STD; - break; - case 3400000: - dev->slave_cfg |= DW_IC_CON_SPEED_HIGH; - break; - default: - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } } static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index ea9578ab19a1..d42558d1b002 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { - u32 sda_falling_time, scl_falling_time; u32 reg, comp_param1; - u32 hcnt, lcnt; int ret; ret = i2c_dw_acquire_lock(dev); @@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) /* Disable the adapter. */ __i2c_dw_enable_and_wait(dev, false); - /* Set standard and fast speed deviders for high/low periods. */ - sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ - scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ - - /* Set SCL timing parameters for standard-mode. */ - if (dev->ss_hcnt && dev->ss_lcnt) { - hcnt = dev->ss_hcnt; - lcnt = dev->ss_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 4000, /* tHD;STA = tHIGH = 4.0 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 4700, /* tLOW = 4.7 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); - dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - /* Set SCL timing parameters for fast-mode or fast-mode plus. */ - if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { - hcnt = dev->fp_hcnt; - lcnt = dev->fp_lcnt; - } else if (dev->fs_hcnt && dev->fs_lcnt) { - hcnt = dev->fs_hcnt; - lcnt = dev->fs_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 600, /* tHD;STA = tHIGH = 0.6 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 1300, /* tLOW = 1.3 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); - dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) == - DW_IC_CON_SPEED_HIGH) { - if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) - != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { - dev_err(dev->dev, "High Speed not supported!\n"); - dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK; - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } else if (dev->hs_hcnt && dev->hs_lcnt) { - hcnt = dev->hs_hcnt; - lcnt = dev->hs_lcnt; - dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); - dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", - hcnt, lcnt); - } - } - /* Configure SDA Hold Time if required. */ reg = dw_readl(dev, DW_IC_COMP_VERSION); if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { -- cgit v1.2.3 From 3991c5c80beaf7eb9bce61e0b2f8f449e351a38e Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:24 +0800 Subject: i2c: Switch to using gpiod interface for gpio bus recovery Currently the i2c gpio recovery code uses gpio integer interface instead of the gpiod. This change switch the core code to use the gpiod while still retaining compatibility with the gpio integer interface. This will allow individual driver to be updated and tested individual to switch to using the gpiod interface. Reviewed-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 706164b4c5be..fdc6a9d1394e 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -134,17 +134,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* i2c bus recovery routines */ static int get_scl_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->scl_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod); } static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - gpio_set_value(adap->bus_recovery_info->scl_gpio, val); + gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val); } static int get_sda_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->sda_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) @@ -159,6 +159,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); return ret; } + bri->scl_gpiod = gpio_to_desc(bri->scl_gpio); if (bri->get_sda) { if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { @@ -167,6 +168,7 @@ static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) bri->sda_gpio); bri->get_sda = NULL; } + bri->sda_gpiod = gpio_to_desc(bri->sda_gpio); } return ret; @@ -176,10 +178,13 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - if (bri->get_sda) + if (bri->get_sda) { gpio_free(bri->sda_gpio); + bri->sda_gpiod = NULL; + } gpio_free(bri->scl_gpio); + bri->scl_gpiod = NULL; } /* @@ -277,6 +282,14 @@ static void i2c_init_recovery(struct i2c_adapter *adap) goto err; } + if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) { + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + if (bri->sda_gpiod) + bri->get_sda = get_sda_gpio_value; + return; + } + /* Generic GPIO recovery */ if (bri->recover_bus == i2c_generic_gpio_recovery) { if (!gpio_is_valid(bri->scl_gpio)) { -- cgit v1.2.3 From a34a0b6da22540d19e578131bbb60994892473d3 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:25 +0800 Subject: i2c: designware: move i2c_dw_plat_prepare_clk to common Move the i2c_dw_plat_prepare_clk funciton to common file in preparation for its use also by the master driver. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 13 +++++++++++++ drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-platdrv.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index d1a69372432f..b79f34245930 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -21,6 +21,7 @@ * ---------------------------------------------------------------------------- * */ +#include #include #include #include @@ -185,6 +186,18 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +{ + if (IS_ERR(i_dev->clk)) + return PTR_ERR(i_dev->clk); + + if (prepare) + return clk_prepare_enable(i_dev->clk); + + clk_disable_unprepare(i_dev->clk); + return 0; +} + int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { int ret; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 21bf619a86c5..e80a14c40347 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -301,6 +301,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); +int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 293f586d78d2..6a3fd8d7c273 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -203,18 +203,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) dev->mode = DW_IC_SLAVE; } -static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) -{ - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); - - if (prepare) - return clk_prepare_enable(i_dev->clk); - - clk_disable_unprepare(i_dev->clk); - return 0; -} - static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) { u32 param, tx_fifo_depth, rx_fifo_depth; -- cgit v1.2.3 From 0326f9f801b2411811906361db870ccdada98b92 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:26 +0800 Subject: i2c: designware: rename i2c_dw_plat_prepare_clk to i2c_dw_prepare_clk For consistency with the rest of the file rename function and parameter to be consistent with the reset of the common file. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 10 +++++----- drivers/i2c/busses/i2c-designware-core.h | 2 +- drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index b79f34245930..3d684c6650b5 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -186,15 +186,15 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) { - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); if (prepare) - return clk_prepare_enable(i_dev->clk); + return clk_prepare_enable(dev->clk); - clk_disable_unprepare(i_dev->clk); + clk_disable_unprepare(dev->clk); return 0; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e80a14c40347..33c6c8f03061 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -301,7 +301,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); -int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare); +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 6a3fd8d7c273..6e0fd94faba1 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -332,7 +332,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure_master(dev); dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!i2c_dw_plat_prepare_clk(dev, true)) { + if (!i2c_dw_prepare_clk(dev, true)) { dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; if (!dev->sda_hold_time && ht) @@ -436,7 +436,7 @@ static int dw_i2c_plat_suspend(struct device *dev) } i_dev->disable(i_dev); - i2c_dw_plat_prepare_clk(i_dev, false); + i2c_dw_prepare_clk(i_dev, false); i_dev->suspended = true; @@ -455,7 +455,7 @@ static int dw_i2c_plat_resume(struct device *dev) return 0; } - i2c_dw_plat_prepare_clk(i_dev, true); + i2c_dw_prepare_clk(i_dev, true); i_dev->init(i_dev); i_dev->suspended = false; -- cgit v1.2.3 From ca382f5b38f367b656c8fd9a0fb93d8f54843520 Mon Sep 17 00:00:00 2001 From: Tim Sander Date: Thu, 2 Nov 2017 10:40:27 +0800 Subject: i2c: designware: add i2c gpio recovery option This patch contains much input from Phil Reid and has been tested on Intel/Altera Cyclone V SOC Hardware with Altera GPIO's for the SCL and SDA GPIO's. Acked-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Signed-off-by: Tim Sander Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 6 +++- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 57 ++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 3d684c6650b5..6b82809647dc 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -230,7 +230,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { if (timeout <= 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + i2c_recover_bus(&dev->adapter); + + if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) + return -ETIMEDOUT; + return 0; } timeout--; usleep_range(1000, 1100); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 33c6c8f03061..d58a336521bf 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -286,6 +286,7 @@ struct dw_i2c_dev { void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int mode; + struct i2c_bus_recovery_info rinfo; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 418c233075d3..ae691884d071 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -25,11 +25,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "i2c-designware-core.h" @@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); ret = -ETIMEDOUT; goto done; @@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +static void i2c_dw_prepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_disable(dev); + reset_control_assert(dev->rst); + i2c_dw_prepare_clk(dev, false); +} + +static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_prepare_clk(dev, true); + reset_control_deassert(dev->rst); + i2c_dw_init_master(dev); +} + +static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) +{ + struct i2c_bus_recovery_info *rinfo = &dev->rinfo; + struct i2c_adapter *adap = &dev->adapter; + struct gpio_desc *gpio; + int r; + + gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); + if (r == -ENOENT) + return 0; + return r; + } + rinfo->scl_gpiod = gpio; + + gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rinfo->sda_gpiod = gpio; + + rinfo->recover_bus = i2c_generic_scl_recovery; + rinfo->prepare_recovery = i2c_dw_prepare_recovery; + rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; + adap->bus_recovery_info = rinfo; + + dev_info(dev->dev, "running with gpio recovery mode! scl%s", + rinfo->sda_gpiod ? ",sda" : ""); + + return 0; +} + int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; @@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) return ret; } + ret = i2c_dw_init_recovery_info(dev); + if (ret) + return ret; + /* * Increment PM usage count during adapter registration in order to * avoid possible spurious runtime suspend when adapter device is -- cgit v1.2.3 From ad36a27959cabb27dfde35ff103d03b22f6ddb36 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:28 +0800 Subject: i2c: imx: switch to using gpiod for bus recovery gpios Change the driver to use the gpio descriptors for the bus recovery information instead of the deprecated integer interface. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f96830ffd9f1..c4cf26571b66 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, "gpio"); - rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0); - rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0); + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_OUT_HIGH); + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_IN); - if (rinfo->sda_gpio == -EPROBE_DEFER || - rinfo->scl_gpio == -EPROBE_DEFER) { + if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || + PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { return -EPROBE_DEFER; - } else if (!gpio_is_valid(rinfo->sda_gpio) || - !gpio_is_valid(rinfo->scl_gpio) || + } else if (IS_ERR(rinfo->sda_gpiod) || + IS_ERR(rinfo->scl_gpiod) || IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); return 0; } - dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", - rinfo->scl_gpio, rinfo->sda_gpio); + dev_dbg(&pdev->dev, "using scl%s for recovery\n", + rinfo->sda_gpiod ? ",sda" : ""); rinfo->prepare_recovery = i2c_imx_prepare_recovery; rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; - rinfo->recover_bus = i2c_generic_gpio_recovery; + rinfo->recover_bus = i2c_generic_scl_recovery; i2c_imx->adapter.bus_recovery_info = rinfo; return 0; -- cgit v1.2.3 From cd2428c368a66c4d61cd416a4f0ad453ce6d57cd Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:29 +0800 Subject: i2c: davinci: switch to using gpiod for bus recovery gpios Change the driver to use the gpio descriptors for the bus recovery information instead of the deprecated integer interface. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Reviewed-by: Sekhar Nori Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 2ead9b9eebb7..2afb12a89eb3 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -294,7 +294,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) } /* - * This routine does i2c bus recovery by using i2c_generic_gpio_recovery + * This routine does i2c bus recovery by using i2c_generic_scl_recovery * which is provided by I2C Bus recovery infrastructure. */ static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap) @@ -316,7 +316,7 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap) } static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { - .recover_bus = i2c_generic_gpio_recovery, + .recover_bus = i2c_generic_scl_recovery, .prepare_recovery = davinci_i2c_prepare_recovery, .unprepare_recovery = davinci_i2c_unprepare_recovery, }; @@ -769,6 +769,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) struct davinci_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem; + struct i2c_bus_recovery_info *rinfo; int r, irq; irq = platform_get_irq(pdev, 0); @@ -869,9 +870,18 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (dev->pdata->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; else if (dev->pdata->scl_pin) { - adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; - adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; - adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; + rinfo = &davinci_i2c_gpio_recovery_info; + adap->bus_recovery_info = rinfo; + r = gpio_request_one(dev->pdata->scl_pin, GPIOF_OPEN_DRAIN | + GPIOF_OUT_INIT_HIGH, "i2c-scl"); + if (r) + goto err_unuse_clocks; + rinfo->scl_gpiod = gpio_to_desc(dev->pdata->scl_pin); + + r = gpio_request_one(dev->pdata->sda_pin, GPIOF_IN, "i2c-sda"); + if (r) + goto err_unuse_clocks; + rinfo->sda_gpiod = gpio_to_desc(dev->pdata->scl_pin); } adap->nr = pdev->id; -- cgit v1.2.3 From e1eb7d28c0753ec3e5ff9dce7880c243ffdfd4b3 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Thu, 2 Nov 2017 10:40:30 +0800 Subject: i2c: remove legacy integer scl/sda gpio for recovery Remove all reference to code related to using integer based ids for scl/sda gpio for bus recovery. All in tree drivers are now using the gpio descriptors to specific the required gpios. Reviewed-by: Andy Shevchenko Signed-off-by: Phil Reid Reviewed-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 78 ++------------------------------------------- 1 file changed, 2 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index fdc6a9d1394e..54ffc8da40df 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -147,46 +147,6 @@ static int get_sda_gpio_value(struct i2c_adapter *adap) return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } -static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - struct device *dev = &adap->dev; - int ret = 0; - - ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | - GPIOF_OUT_INIT_HIGH, "i2c-scl"); - if (ret) { - dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); - return ret; - } - bri->scl_gpiod = gpio_to_desc(bri->scl_gpio); - - if (bri->get_sda) { - if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { - /* work without SDA polling */ - dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", - bri->sda_gpio); - bri->get_sda = NULL; - } - bri->sda_gpiod = gpio_to_desc(bri->sda_gpio); - } - - return ret; -} - -static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->get_sda) { - gpio_free(bri->sda_gpio); - bri->sda_gpiod = NULL; - } - - gpio_free(bri->scl_gpio); - bri->scl_gpiod = NULL; -} - /* * We are generating clock pulses. ndelay() determines durating of clk pulses. * We will generate clock with rate 100 KHz and so duration of both clock levels @@ -195,7 +155,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) #define RECOVERY_NDELAY 5000 #define RECOVERY_CLK_CNT 9 -static int i2c_generic_recovery(struct i2c_adapter *adap) +int i2c_generic_scl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; int i = 0, val = 1, ret = 0; @@ -237,28 +197,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) return ret; } - -int i2c_generic_scl_recovery(struct i2c_adapter *adap) -{ - return i2c_generic_recovery(adap); -} EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); -int i2c_generic_gpio_recovery(struct i2c_adapter *adap) -{ - int ret; - - ret = i2c_get_gpios_for_recovery(adap); - if (ret) - return ret; - - ret = i2c_generic_recovery(adap); - i2c_put_gpios_for_recovery(adap); - - return ret; -} -EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery); - int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) @@ -290,21 +230,7 @@ static void i2c_init_recovery(struct i2c_adapter *adap) return; } - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - err_str = "invalid SCL gpio"; - goto err; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - - bri->get_scl = get_scl_gpio_value; - bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { + if (bri->recover_bus == i2c_generic_scl_recovery) { /* Generic SCL recovery */ if (!bri->set_scl || !bri->get_scl) { err_str = "no {get|set}_scl() found"; -- cgit v1.2.3 From f289800af1fd4379403f2630e7e9420401a4cd8e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:27 +0100 Subject: i2c: sh_mobile: remove redundant initialization Following the documentation, we initialize the HW before each START in start_ch(). No need to do the same in activate_ch(). Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c03acdf71397..0ac152586e74 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -303,16 +303,6 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); clk_prepare_enable(pd->clk); - - /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); - - /* Mask all interrupts */ - iic_wr(pd, ICIC, 0); - - /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl & 0xff); - iic_wr(pd, ICCH, pd->icch & 0xff); } static void deactivate_ch(struct sh_mobile_i2c_data *pd) -- cgit v1.2.3 From 3f3a513985ce55d69922cc9b5a0e095432cdfbc4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:28 +0100 Subject: i2c: sh_mobile: remove redundant deinitialization No need to clear the interrupt registers because right after that we disable the IP core which will reload registers with their initial values anyhow. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 0ac152586e74..cbaed24fb18f 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -307,10 +307,6 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) static void deactivate_ch(struct sh_mobile_i2c_data *pd) { - /* Clear/disable interrupts */ - iic_wr(pd, ICSR, 0); - iic_wr(pd, ICIC, 0); - /* Disable channel */ iic_set_clr(pd, ICCR, 0, ICCR_ICE); -- cgit v1.2.3 From 91a5e63e3f9879e5030064a3c0d23c3777c4f4d0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:29 +0100 Subject: i2c: sh_mobile: manually "inline" two short functions Those two functions are very short and only called once. The code becomes easier to understand if the code is directly put into the main xfer function. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index cbaed24fb18f..02c2912bebb4 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -298,23 +298,6 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) return 0; } -static void activate_ch(struct sh_mobile_i2c_data *pd) -{ - /* Wake up device and enable clock */ - pm_runtime_get_sync(pd->dev); - clk_prepare_enable(pd->clk); -} - -static void deactivate_ch(struct sh_mobile_i2c_data *pd) -{ - /* Disable channel */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); - - /* Disable clock and mark device as idle */ - clk_disable_unprepare(pd->clk); - pm_runtime_put_sync(pd->dev); -} - static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op, unsigned char data) { @@ -717,7 +700,9 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, int i; long timeout; - activate_ch(pd); + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); + clk_prepare_enable(pd->clk); /* Process all messages */ for (i = 0; i < num; i++) { @@ -754,7 +739,12 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, break; } - deactivate_ch(pd); + /* Disable channel */ + iic_set_clr(pd, ICCR, 0, ICCR_ICE); + + /* Disable clock and mark device as idle */ + clk_disable_unprepare(pd->clk); + pm_runtime_put_sync(pd->dev); if (!err) err = num; -- cgit v1.2.3 From 832a522a3ef5e96b517163ee7d4c249545d88626 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:30 +0100 Subject: i2c: sh_mobile: use direct writes when accessing ICE bit ICE bit is for resetting the module. Other bits don't matter then, so we don't need to use the iic_set_clr() function but can use iic_wr(). Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 02c2912bebb4..72c9483db769 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -620,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, if (do_init) { /* Initialize channel registers */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + iic_wr(pd, ICCR, 0); /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); + iic_wr(pd, ICCR, ICCR_ICE); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); @@ -740,7 +740,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, } /* Disable channel */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + iic_wr(pd, ICCR, 0); /* Disable clock and mark device as idle */ clk_disable_unprepare(pd->clk); -- cgit v1.2.3 From a4d16493be406273320f152814c33ccdb17dcf91 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Nov 2017 13:47:31 +0100 Subject: i2c: sh_mobile: shorten exit of xfer routine We can use the ternary operator for easier reading. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 72c9483db769..ebd146ccb244 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -746,9 +746,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, clk_disable_unprepare(pd->clk); pm_runtime_put_sync(pd->dev); - if (!err) - err = num; - return err; + return err ?: num; } static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) -- cgit v1.2.3 From 91701ae85dff9703335b5912673df75f4b6f4c53 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Nov 2017 09:50:37 +0100 Subject: i2c: sh_mobile: let RuntimePM do the clock handling No need to do it manually. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ebd146ccb244..80561ffbcf7b 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -702,7 +702,6 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); - clk_prepare_enable(pd->clk); /* Process all messages */ for (i = 0; i < num; i++) { @@ -743,7 +742,6 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, iic_wr(pd, ICCR, 0); /* Disable clock and mark device as idle */ - clk_disable_unprepare(pd->clk); pm_runtime_put_sync(pd->dev); return err ?: num; -- cgit v1.2.3 From 2967f9ca8b0dc8d924e0f14c55d1e73d9c6c4975 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 9 Nov 2017 23:20:53 +0100 Subject: i2c: sh_mobile: avoid unnecessary register read There is no data when the first WAIT interrupt arrives. No need to read something then. Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 80561ffbcf7b..40a66d466c3c 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -433,8 +433,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) break; } data = i2c_op(pd, OP_RX_STOP_DATA, 0); - } else + } else if (real_pos >= 0) { data = i2c_op(pd, OP_RX, 0); + } if (real_pos >= 0) pd->msg->buf[real_pos] = data; -- cgit v1.2.3 From a4fde7e5c9d6432ba863ee53debf27f10b370678 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 10 Nov 2017 12:52:10 +0100 Subject: i2c: sh_mobile: send STOP according to datasheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We initiate STOP (or REP_START) on the second last WAIT interrupt currently. This works fine but is not according to the datasheet which says to do it on the last WAIT interrupt. This also simplifies the code quite a lot, so let's do it. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 40a66d466c3c..c904be631db3 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -40,21 +40,21 @@ /* BUS: S A8 ACK P(*) */ /* IRQ: DTE WAIT */ /* ICIC: */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 */ /* */ /* 1 byte transmit */ /* BUS: S A8 ACK D8(1) ACK P(*) */ /* IRQ: DTE WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) */ /* */ /* 2 byte transmit */ /* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */ /* IRQ: DTE WAIT WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) D8(2) */ /* */ /* 3 bytes or more, +---------+ gets repeated */ @@ -113,7 +113,6 @@ enum sh_mobile_i2c_op { OP_TX_FIRST, OP_TX, OP_TX_STOP, - OP_TX_STOP_DATA, OP_TX_TO_RX, OP_RX, OP_RX_STOP, @@ -319,10 +318,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, case OP_TX: /* write data */ iic_wr(pd, ICDR, data); break; - case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ - iic_wr(pd, ICDR, data); - /* fallthrough */ - case OP_TX_STOP: /* issue a stop */ + case OP_TX_STOP: /* issue a stop (or rep_start) */ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; @@ -356,11 +352,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) return pd->pos == -1; } -static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) -{ - return pd->pos == pd->msg->len - 1; -} - static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, unsigned char *buf) { @@ -378,20 +369,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) unsigned char data; if (pd->pos == pd->msg->len) { - /* Send stop if we haven't yet (DMA case) */ - if (pd->send_stop && pd->stop_after_dma) - i2c_op(pd, OP_TX_STOP, 0); + i2c_op(pd, OP_TX_STOP, 0); return 1; } sh_mobile_i2c_get_data(pd, &data); - - if (sh_mobile_i2c_is_last_byte(pd)) - i2c_op(pd, OP_TX_STOP_DATA, data); - else if (sh_mobile_i2c_is_first_byte(pd)) - i2c_op(pd, OP_TX_FIRST, data); - else - i2c_op(pd, OP_TX, data); + i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data); pd->pos++; return 0; -- cgit v1.2.3 From 4ed152c4daf32d2cd4a5285f3aaca3a4c89a31fb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Nov 2017 15:32:21 +0100 Subject: i2c: sh_mobile: make sure to not accidently trigger STOP The datasheet was a bit vague, but after consultation with HW designers, we came to the conclusion that we should set the SCP bit always when dealing only with the ICE bit. A set SCP bit is ignored, and thus fine, a cleared one may trigger STOP on the bus. Signed-off-by: Wolfram Sang Tested-by: Jacopo Mondi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c904be631db3..bc1605a31534 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -604,10 +604,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, if (do_init) { /* Initialize channel registers */ - iic_wr(pd, ICCR, 0); + iic_wr(pd, ICCR, ICCR_SCP); /* Enable channel and configure rx ack */ - iic_wr(pd, ICCR, ICCR_ICE); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); @@ -723,7 +723,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, } /* Disable channel */ - iic_wr(pd, ICCR, 0); + iic_wr(pd, ICCR, ICCR_SCP); /* Disable clock and mark device as idle */ pm_runtime_put_sync(pd->dev); -- cgit v1.2.3 From 10c9ef045a7e19e9fd4c829c7321f9d2048808c0 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 28 Nov 2017 11:09:10 +0800 Subject: i2c: core: fix compile issue related to incorrect gpio header The correct header to include for the gpiod interface is . Fixes: 3991c5c80beaf7eb9 ("i2c: Switch to using gpiod interface for gpio bus recovery") Signed-off-by: Phil Reid Reviewed-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 54ffc8da40df..bf52cca87363 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 4d67c2e7f60dbf5a3cf65f6773c73e12970b0fe0 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 28 Nov 2017 11:09:11 +0800 Subject: i2c: designware: fix building driver as module The designware core and platform are built as separate modules. Export i2c_dw_prepare_clk() so it can be used by the platform driver. Fixes: a34a0b6da22540d19e57 ("i2c: designware: move i2c_dw_plat_prepare_clk to common") Signed-off-by: Phil Reid Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 6b82809647dc..27ebd90de43b 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -197,6 +197,7 @@ int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) clk_disable_unprepare(dev->clk); return 0; } +EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { -- cgit v1.2.3 From 14911c6f48ec9571343ac36ae02f2db68bf9e7f9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 28 Nov 2017 16:53:32 +0100 Subject: i2c: gpio: add fault injector Add fault injection capabilities to the i2c-gpio driver. When connected to another I2C bus, it can create unusual states which the other I2C bus master driver needs to handle. Only for debugging! Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 8 +++ drivers/i2c/busses/i2c-gpio.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 009345d8f49d..a9805c7cb305 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -603,6 +603,14 @@ config I2C_GPIO This is a very simple bitbanging I2C driver utilizing the arch-neutral GPIO API to control the SCL and SDA lines. +config I2C_GPIO_FAULT_INJECTOR + bool "GPIO-based fault injector" + depends on I2C_GPIO + help + This adds some functionality to the i2c-gpio driver which can inject + faults to an I2C bus, so another bus master can be stress-tested. + This is for debugging. If unsure, say 'no'. + config I2C_HIGHLANDER tristate "Highlander FPGA SMBus interface" depends on SH_HIGHLANDER diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d80ea6ce91bb..3312ef981cb7 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -7,6 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include +#include #include #include #include @@ -23,6 +25,9 @@ struct i2c_gpio_private_data { struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR + struct dentry *debug_dir; +#endif }; /* @@ -64,6 +69,108 @@ static int i2c_gpio_getscl(void *data) return gpiod_get_value(priv->scl); } +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR +static struct dentry *i2c_gpio_debug_dir; + +#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) +#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) +#define getsda(bd) ((bd)->getsda((bd)->data)) +#define getscl(bd) ((bd)->getscl((bd)->data)) + +#define WIRE_ATTRIBUTE(wire) \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") + +WIRE_ATTRIBUTE(scl); +WIRE_ATTRIBUTE(sda); + +static int fops_incomplete_transfer_set(void *data, u64 addr) +{ + struct i2c_gpio_private_data *priv = data; + struct i2c_algo_bit_data *bit_data = &priv->bit_data; + int i, pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_lock_adapter(&priv->adap); + + /* START condition */ + setsda(bit_data, 0); + udelay(bit_data->udelay); + + /* Send ADDR+RD, request ACK, don't send STOP */ + for (i = 8; i >= 0; i--) { + setscl(bit_data, 0); + udelay(bit_data->udelay / 2); + setsda(bit_data, (pattern >> i) & 1); + udelay((bit_data->udelay + 1) / 2); + setscl(bit_data, 1); + udelay(bit_data->udelay); + } + + i2c_unlock_adapter(&priv->adap); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); + +static void i2c_gpio_fault_injector_init(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + /* + * If there will be a debugfs-dir per i2c adapter somewhen, put the + * 'fault-injector' dir there. Until then, we have a global dir with + * all adapters as subdirs. + */ + if (!i2c_gpio_debug_dir) { + i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); + if (!i2c_gpio_debug_dir) + return; + } + + priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); + if (!priv->debug_dir) + return; + + debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); + debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, + priv, &fops_incomplete_transfer); +} + +static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debug_dir); +} +#else +static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} +static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} +#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ + static void of_i2c_gpio_get_props(struct device_node *np, struct i2c_gpio_platform_data *pdata) { @@ -228,6 +335,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) pdata->scl_is_output_only ? ", no clock stretching" : ""); + i2c_gpio_fault_injector_init(pdev); + return 0; } @@ -236,6 +345,8 @@ static int i2c_gpio_remove(struct platform_device *pdev) struct i2c_gpio_private_data *priv; struct i2c_adapter *adap; + i2c_gpio_fault_injector_exit(pdev); + priv = platform_get_drvdata(pdev); adap = &priv->adap; -- cgit v1.2.3 From e94bc5d18be03dac8e9d73d30c5523728edeff76 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:02 +0100 Subject: i2c: add helpers to ease DMA handling One helper checks if DMA is suitable and optionally creates a bounce buffer, if not. The other function returns the bounce buffer and makes sure the data is properly copied back to the message. Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index bf52cca87363..b6ca97f0322b 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -2200,6 +2200,52 @@ void i2c_put_adapter(struct i2c_adapter *adap) } EXPORT_SYMBOL(i2c_put_adapter); +/** + * i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg + * @msg: the message to be checked + * @threshold: the minimum number of bytes for which using DMA makes sense + * + * Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO. + * Or a valid pointer to be used with DMA. After use, release it by + * calling i2c_release_dma_safe_msg_buf(). + * + * This function must only be called from process context! + */ +u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold) +{ + if (msg->len < threshold) + return NULL; + + if (msg->flags & I2C_M_DMA_SAFE) + return msg->buf; + + pr_debug("using bounce buffer for addr=0x%02x, len=%d\n", + msg->addr, msg->len); + + if (msg->flags & I2C_M_RD) + return kzalloc(msg->len, GFP_KERNEL); + else + return kmemdup(msg->buf, msg->len, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf); + +/** + * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg + * @msg: the message to be synced with + * @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL. + */ +void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf) +{ + if (!buf || buf == msg->buf) + return; + + if (msg->flags & I2C_M_RD) + memcpy(msg->buf, buf, msg->len); + + kfree(buf); +} +EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf); + MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 978336d48d887d6deb7793e0d20a4673f357fb8e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:03 +0100 Subject: i2c: dev: mark RDWR buffers as DMA_SAFE Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 2cab27a68479..036a03f0d0a6 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -264,6 +264,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, res = PTR_ERR(msgs[i].buf); break; } + /* memdup_user allocates with GFP_KERNEL, so DMA is ok */ + msgs[i].flags |= I2C_M_DMA_SAFE; /* * If the message length is received from the slave (similar -- cgit v1.2.3 From 8a91732b3b33454d8034e7be5c8342f028ea772e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:04 +0100 Subject: i2c: refactor i2c_master_{send_recv} Those two functions are very similar, the only differences are that one needs the I2C_M_RD flag for its message while the other one needs the buffer casted to drop the const. Introduce a generic helper which allows to specify the flags (also needed later for DMA safe variants of these calls) and let the casting be done in the inlining functions which are now calling the new helper function. Signed-off-by: Wolfram Sang Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-base.c | 64 +++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index b6ca97f0322b..bb34a5d41133 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1911,63 +1911,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) EXPORT_SYMBOL(i2c_transfer); /** - * i2c_master_send - issue a single I2C message in master transmit mode + * i2c_transfer_buffer_flags - issue a single I2C message transferring data + * to/from a buffer * @client: Handle to slave device - * @buf: Data that will be written to the slave - * @count: How many bytes to write, must be less than 64k since msg.len is u16 + * @buf: Where the data is stored + * @count: How many bytes to transfer, must be less than 64k since msg.len is u16 + * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads * - * Returns negative errno, or else the number of bytes written. + * Returns negative errno, or else the number of bytes transferred. */ -int i2c_master_send(const struct i2c_client *client, const char *buf, int count) +int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, + int count, u16 flags) { int ret; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; - - ret = i2c_transfer(adap, &msg, 1); - - /* - * If everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1) ? count : ret; -} -EXPORT_SYMBOL(i2c_master_send); - -/** - * i2c_master_recv - issue a single I2C message in master receive mode - * @client: Handle to slave device - * @buf: Where to store data read from slave - * @count: How many bytes to read, must be less than 64k since msg.len is u16 - * - * Returns negative errno, or else the number of bytes read. - */ -int i2c_master_recv(const struct i2c_client *client, char *buf, int count) -{ - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - int ret; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; + struct i2c_msg msg = { + .addr = client->addr, + .flags = flags | (client->flags & I2C_M_TEN), + .len = count, + .buf = buf, + }; - ret = i2c_transfer(adap, &msg, 1); + ret = i2c_transfer(client->adapter, &msg, 1); /* - * If everything went ok (i.e. 1 msg received), return #bytes received, - * else error code. + * If everything went ok (i.e. 1 msg transferred), return #bytes + * transferred, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_transfer_buffer_flags); /* ---------------------------------------------------- * the i2c address scanning function -- cgit v1.2.3 From 8a77821e74d6d5ba2eacd4b450684ae6cbe012a0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:06 +0100 Subject: i2c: smbus: use DMA safe buffers for emulated SMBus transactions For all block commands, try to allocate a DMA safe buffer and mark it accordingly. Only use the stack, if the buffers cannot be allocated. Signed-off-by: Wolfram Sang Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-smbus.c | 45 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 4bb9927afd01..1238c94fe5a1 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -18,6 +18,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -291,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, } EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); +static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) +{ + bool is_read = msg->flags & I2C_M_RD; + unsigned char *dma_buf; + + dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL); + if (!dma_buf) + return; + + msg->buf = dma_buf; + msg->flags |= I2C_M_DMA_SAFE; + + if (init_val) + msg->buf[0] = init_val; +} + /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, @@ -368,6 +385,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -376,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: @@ -389,16 +409,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + msg[0].len = data->block[0] + 2; + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; + msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { @@ -407,8 +432,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i <= data->block[0]; i++) - msgbuf0[i] = data->block[i]; + msg[0].buf[i] = data->block[i]; } break; default: @@ -456,14 +483,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < data->block[0]; i++) - data->block[i+1] = msgbuf1[i]; + data->block[i + 1] = msg[1].buf[i]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: - for (i = 0; i < msgbuf1[0] + 1; i++) - data->block[i] = msgbuf1[i]; + for (i = 0; i < msg[1].buf[0] + 1; i++) + data->block[i] = msg[1].buf[i]; break; } + + if (msg[0].flags & I2C_M_DMA_SAFE) + kfree(msg[0].buf); + if (msg[1].flags & I2C_M_DMA_SAFE) + kfree(msg[1].buf); + return 0; } -- cgit v1.2.3 From fe23aa9a1670b8800b251fc0400425e765c81880 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 4 Nov 2017 21:20:08 +0100 Subject: i2c: sh_mobile: use core helper to decide when to use DMA This ensures that we fall back to PIO if the message length is too small for DMA being useful. Otherwise, we use DMA. A bounce buffer might be applied by the helper if the original message buffer is not DMA safe. Reviewed-by: Jonathan Cameron Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index bc1605a31534..b01607b4fce2 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -144,6 +144,7 @@ struct sh_mobile_i2c_data { struct dma_chan *dma_rx; struct scatterlist sg; enum dma_data_direction dma_direction; + u8 *dma_buf; }; struct sh_mobile_dt_config { @@ -501,6 +502,8 @@ static void sh_mobile_i2c_dma_callback(void *data) pd->pos = pd->msg->len; pd->stop_after_dma = true; + i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf); + iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); } @@ -561,7 +564,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) if (IS_ERR(chan)) return; - dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir); + dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir); if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(pd->dev, "dma map failed, using PIO\n"); return; @@ -618,7 +621,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, pd->pos = -1; pd->sr = 0; - if (pd->msg->len > 8) + pd->dma_buf