Re: [PATCH v2 6/8] i2c: designware: Separate timing parameter setting from HW initalization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2018-06-01 at 16:47 +0300, Jarkko Nikula wrote:
> Mixed timing parameter validation, calculation and their debug prints
> with HW initialization in i2c_dw_init_master() and i2c_dw_init_slave()
> has been bothering me some time.
> 
> It makes function a little bit unclear to follow, doesn't show what
> steps
> are needed to do only once during probe and what are needed whenever
> HW
> needs to be reinitialized. Also those debug prints show information
> that
> doesn't change runtime and thus are also needlessly printed multiple
> times
> whenever HW is reinitialized.
> 
> Thus let the i2c_dw_init_master() and i2c_dw_init_slave() to do only
> HW
> initialization and move out one time parameter setting and debug
> prints
> to separate functions which are called only during probe.
> 
> Signed-off-by: Jarkko Nikula <jarkko.nikula@xxxxxxxxxxxxxxx>
> ---
> v2:
> - SDA hold time configuration change moved to a new patch
> - Indentation change around i2c_dw_scl_hcnt()/i2c_dw_scl_lcnt() and
>   i2c_dw_clk_rate() cleanup moved to a new patch
> - fp_str pointing to empty or " Plus" string for simpler fast
> mode/fast
>   mode plus debug prints in this and another patch in this series
> ---
>  drivers/i2c/busses/i2c-designware-master.c | 128 +++++++++++++-------
> -
>  1 file changed, 77 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-designware-master.c
> b/drivers/i2c/busses/i2c-designware-master.c
> index 6557e163065e..e3a56c8e33c7 100644
> --- a/drivers/i2c/busses/i2c-designware-master.c
> +++ b/drivers/i2c/busses/i2c-designware-master.c
> @@ -46,85 +46,77 @@ static void i2c_dw_configure_fifo_master(struct
> dw_i2c_dev *dev)
>  }
>  
>  static void i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
> -{
> -	i2c_dw_set_sda_hold(dev);
> -}
> -
> -/**
> - * i2c_dw_init() - Initialize the designware I2C master hardware
> - * @dev: device private data
> - *
> - * This functions configures and enables the I2C master.
> - * This function is called during I2C init function, and in case of
> timeout at
> - * run time.
> - */
> -static int i2c_dw_init_master(struct dw_i2c_dev *dev)
>  {
>  	u32 ic_clk = i2c_dw_clk_rate(dev);
> -	u32 hcnt, lcnt;
> +	const char *fp_str = "";
>  	u32 comp_param1;
>  	u32 sda_falling_time, scl_falling_time;
>  	int ret;
>  
>  	ret = i2c_dw_acquire_lock(dev);
>  	if (ret)
> -		return ret;
> -
> +		return;

Shouldn't we return an error code to the caller?
Previously we abort initialization IIUC and now silently skip the timing
settings completely. Feels like a regression.

>  	comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
> +	i2c_dw_release_lock(dev);
>  
> -	/* Disable the adapter */
> -	__i2c_dw_disable(dev);
> -
> -	/* Set standard and fast speed deviders for high/low periods
> */
> -
> +	/* Set standard and fast speed dividers 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 =
> +	/* Calculate SCL timing parameters for standard mode if not
> set */
> +	if (!dev->ss_hcnt || !dev->ss_lcnt) {
> +		dev->ss_hcnt =
>  			i2c_dw_scl_hcnt(ic_clk,
>  					4000,	/* tHD;STA =
> tHIGH = 4.0 us */
>  					sda_falling_time,
>  					0,	/* 0: DW default,
> 1: Ideal */
>  					0);	/* No offset */
> -		lcnt =
> +		dev->ss_lcnt =
>  			i2c_dw_scl_lcnt(ic_clk,
>  					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 =
> +	dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n",
> +		dev->ss_hcnt, dev->ss_lcnt);
> +
> +	/*
> +	 * Set SCL timing parameters for fast mode or fast mode plus.
> Only
> +	 * difference is the timing parameter values since the
> registers are
> +	 * the same.
> +	 */
> +	if (dev->clk_freq == 1000000) {
> +		/*
> +		 * Check are fast mode plus parameters available and
> use
> +		 * fast mode if not.
> +		 */
> +		if (dev->fp_hcnt && dev->fp_lcnt) {
> +			dev->fs_hcnt = dev->fp_hcnt;
> +			dev->fs_lcnt = dev->fp_lcnt;
> +			fp_str = " Plus";
> +		}
> +	}
> +	/*
> +	 * Calculate SCL timing parameters for fast mode if not set.
> They are
> +	 * needed also in high speed mode.
> +	 */
> +	if (!dev->fs_hcnt || !dev->fs_lcnt) {
> +		dev->fs_hcnt =
>  			i2c_dw_scl_hcnt(ic_clk,
>  					600,	/* tHD;STA =
> tHIGH = 0.6 us */
>  					sda_falling_time,
>  					0,	/* 0: DW default,
> 1: Ideal */
>  					0);	/* No offset */
> -		lcnt =
> +		dev->fs_lcnt =
>  			i2c_dw_scl_lcnt(ic_clk,
>  					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);
> +	dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n",
> +		fp_str, dev->fs_hcnt, dev->fs_lcnt);
>  
> +	/* Check is high speed possible and fall back to fast mode if
> not */
>  	if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) ==
>  		DW_IC_CON_SPEED_HIGH) {
>  		if ((comp_param1 &
> DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
> @@ -132,16 +124,50 @@ static int i2c_dw_init_master(struct dw_i2c_dev
> *dev)
>  			dev_err(dev->dev, "High Speed not
> supported!\n");
>  			dev->master_cfg &= ~DW_IC_CON_SPEED_MASK;
>  			dev->master_cfg |= DW_IC_CON_SPEED_FAST;
> +			dev->hs_hcnt = 0;
> +			dev->hs_lcnt = 0;
>  		} 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);
> +			dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT
> = %d:%d\n",
> +				dev->hs_hcnt, dev->hs_lcnt);
>  		}
>  	}
>  
> +	i2c_dw_set_sda_hold(dev);
> +}
> +
> +/**
> + * i2c_dw_init() - Initialize the designware I2C master hardware
> + * @dev: device private data
> + *
> + * This functions configures and enables the I2C master.
> + * This function is called during I2C init function, and in case of
> timeout at
> + * run time.
> + */
> +static int i2c_dw_init_master(struct dw_i2c_dev *dev)
> +{
> +	int ret;
> +
> +	ret = i2c_dw_acquire_lock(dev);
> +	if (ret)
> +		return ret;
> +
> +	/* Disable the adapter */
> +	__i2c_dw_disable(dev);
> +
> +	/* Write standard speed timing parameters */
> +	dw_writel(dev, dev->ss_hcnt, DW_IC_SS_SCL_HCNT);
> +	dw_writel(dev, dev->ss_lcnt, DW_IC_SS_SCL_LCNT);
> +
> +	/* Write fast mode/fast mode plus timing parameters */
> +	dw_writel(dev, dev->fs_hcnt, DW_IC_FS_SCL_HCNT);
> +	dw_writel(dev, dev->fs_lcnt, DW_IC_FS_SCL_LCNT);
> +
> +	/* Write high speed timing parameters if supported */
> +	if (dev->hs_hcnt && dev->hs_lcnt) {
> +		dw_writel(dev, dev->hs_hcnt, DW_IC_HS_SCL_HCNT);
> +		dw_writel(dev, dev->hs_lcnt, DW_IC_HS_SCL_LCNT);
> +	}
> +
>  	/* Write SDA hold time if supported */
>  	if (dev->sda_hold_time)
>  		dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);

-- 
Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Intel Finland Oy



[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux