RE: [PATCH] OMAP: I2C: Add mpu wake up latency constraint in i2c

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

 



Hi Ben,

Could you take this patch to i2c tree? The patch has been discussed in linux-omap list, and this version was the one that was agreed to pushed forward.

http://marc.info/?l=linux-omap&m=125907598412786&w=2


I tried it on top of linus' tree and it applied fine. 

- Kalle


> -----Original Message-----
> From: linux-omap-owner@xxxxxxxxxxxxxxx 
> [mailto:linux-omap-owner@xxxxxxxxxxxxxxx] On Behalf Of 
> Jokiniemi Kalle (Nokia-D/Tampere)
> Sent: 25. marraskuuta 2009 20:04
> To: ben-linux@xxxxxxxxx; linux-i2c@xxxxxxxxxxxxxxx
> Cc: linux-omap@xxxxxxxxxxxxxxx; Ujfalusi Peter 
> (Nokia-D/Tampere); Hogander Jouni (Nokia-D/Tampere); 
> khilman@xxxxxxxxxxxxxxxxxxx; ext Kalle Jokiniemi; Moiz 
> Sonasath; Jarkko Nikula; Paul Walmsley; Nishanth Menon
> Subject: [PATCH] OMAP: I2C: Add mpu wake up latency constraint in i2c
> 
> From: ext Kalle Jokiniemi <kalle.jokiniemi@xxxxxxxxx>
> 
> While waiting for completion of the i2c transfer, the MPU 
> could hit OFF mode and cause several msecs of delay that made 
> i2c transfers fail more often. The extra delays and 
> subsequent re-trys cause i2c clocks to be active more often. 
> This has also an negative effect on power consumption.
> 
> Created a mechanism for passing and using the constraint 
> setting function in driver code. The used mpu wake up latency 
> constraints are now set individually per bus, and they are 
> calculated based on clock rate and fifo size.
> 
> Thanks to Jarkko Nikula, Moiz Sonasath, Paul Walmsley, and 
> Nishanth Menon for tuning out the details of this patch.
> 
> Cc: Moiz Sonasath <m-sonasath@xxxxxx>
> Cc: Jarkko Nikula <jhnikula@xxxxxxxxx>
> Cc: Paul Walmsley <paul@xxxxxxxxx>
> Cc: Nishanth Menon <nm@xxxxxx>
> Signed-off-by: Kalle Jokiniemi <kalle.jokiniemi@xxxxxxxxx>
> ---
>  arch/arm/plat-omap/i2c.c      |   54 
> +++++++++++++++++++++++++++++++---------
>  drivers/i2c/busses/i2c-omap.c |   25 ++++++++++++++++---
>  include/linux/i2c-omap.h      |    9 +++++++
>  3 files changed, 72 insertions(+), 16 deletions(-)  create 
> mode 100644 include/linux/i2c-omap.h
> 
> diff --git a/arch/arm/plat-omap/i2c.c 
> b/arch/arm/plat-omap/i2c.c index 8b84839..3c122cd 100644
> --- a/arch/arm/plat-omap/i2c.c
> +++ b/arch/arm/plat-omap/i2c.c
> @@ -26,8 +26,10 @@
>  #include <linux/kernel.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c.h>
> +#include <linux/i2c-omap.h>
>  #include <mach/irqs.h>
>  #include <mach/mux.h>
> +#include <mach/omap-pm.h>
>  
>  #define OMAP_I2C_SIZE		0x3f
>  #define OMAP1_I2C_BASE		0xfffb3800
> @@ -69,14 +71,14 @@ static struct resource i2c_resources[][2] = {
>  		},					\
>  	}
>  
> -static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
> +static struct omap_i2c_bus_platform_data 
> +i2c_pdata[ARRAY_SIZE(i2c_resources)];
>  static struct platform_device omap_i2c_devices[] = {
> -	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
> +	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_pdata[0]),
>  #if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
> -	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
> +	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_pdata[1]),
>  #endif
>  #if	defined(CONFIG_ARCH_OMAP34XX)
> -	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
> +	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_pdata[2]),
>  #endif
>  };
>  
> @@ -100,6 +102,31 @@ static const int omap34xx_pins[][2] = {};
>  
>  #define OMAP_I2C_CMDLINE_SETUP	(BIT(31))
>  
> +#ifdef CONFIG_ARCH_OMAP34XX
> +/*
> + * omap_i2c_set_wfc_mpu_wkup_lat - sets mpu wake up constraint
> + * @dev:	i2c bus device pointer
> + * @val:	latency constraint to set, -1 to disable constraint
> + *
> + * When waiting for completion of a i2c transfer, we need to 
> set a wake 
> +up
> + * latency constraint for the MPU. This is to ensure quick enough 
> +wakeup from
> + * idle, when transfer completes.
> + */
> +static void omap_i2c_set_wfc_mpu_wkup_lat(struct device 
> *dev, int val) 
> +{
> +	omap_pm_set_max_mpu_wakeup_lat(dev, val); } #endif
> +
> +static void __init omap_set_i2c_constraint_func(
> +				struct omap_i2c_bus_platform_data *pd) {
> +	if (cpu_is_omap34xx())
> +		pd->set_mpu_wkup_lat = omap_i2c_set_wfc_mpu_wkup_lat;
> +	else
> +		pd->set_mpu_wkup_lat = NULL;
> +}
> +
>  static void __init omap_i2c_mux_pins(int bus)  {
>  	int scl, sda;
> @@ -180,8 +207,8 @@ static int __init omap_i2c_bus_setup(char *str)
>  	get_options(str, 3, ints);
>  	if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
>  		return 0;
> -	i2c_rate[ints[1] - 1] = ints[2];
> -	i2c_rate[ints[1] - 1] |= OMAP_I2C_CMDLINE_SETUP;
> +	i2c_pdata[ints[1] - 1].clkrate = ints[2];
> +	i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
>  
>  	return 1;
>  }
> @@ -195,9 +222,10 @@ static int __init 
> omap_register_i2c_bus_cmdline(void)
>  {
>  	int i, err = 0;
>  
> -	for (i = 0; i < ARRAY_SIZE(i2c_rate); i++)
> -		if (i2c_rate[i] & OMAP_I2C_CMDLINE_SETUP) {
> -			i2c_rate[i] &= ~OMAP_I2C_CMDLINE_SETUP;
> +	for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
> +		if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
> +			i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
> +			omap_set_i2c_constraint_func(&i2c_pdata[i]);
>  			err = omap_i2c_add_bus(i + 1);
>  			if (err)
>  				goto out;
> @@ -231,9 +259,11 @@ int __init omap_register_i2c_bus(int 
> bus_id, u32 clkrate,
>  			return err;
>  	}
>  
> -	if (!i2c_rate[bus_id - 1])
> -		i2c_rate[bus_id - 1] = clkrate;
> -	i2c_rate[bus_id - 1] &= ~OMAP_I2C_CMDLINE_SETUP;
> +	if (!i2c_pdata[bus_id - 1].clkrate)
> +		i2c_pdata[bus_id - 1].clkrate = clkrate;
> +
> +	omap_set_i2c_constraint_func(&i2c_pdata[bus_id - 1]);
> +	i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
>  
>  	return omap_i2c_add_bus(bus_id);
>  }
> diff --git a/drivers/i2c/busses/i2c-omap.c 
> b/drivers/i2c/busses/i2c-omap.c index 827da08..ac0bfd2 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -37,6 +37,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/clk.h>
>  #include <linux/io.h>
> +#include <linux/i2c-omap.h>
>  
>  /* I2C controller revisions */
>  #define OMAP_I2C_REV_2			0x20
> @@ -165,6 +166,9 @@ struct omap_i2c_dev {
>  	struct clk		*fclk;		/* Functional clock */
>  	struct completion	cmd_complete;
>  	struct resource		*ioarea;
> +	u32			latency;	/* maximum mpu 
> wkup latency */
> +	void			(*set_mpu_wkup_lat)(struct device *dev,
> +						    int latency);
>  	u32			speed;		/* Speed of bus 
> in Khz */
>  	u16			cmd_err;
>  	u8			*buf;
> @@ -508,8 +512,12 @@ static int omap_i2c_xfer_msg(struct 
> i2c_adapter *adap,
>  	 * REVISIT: We should abort the transfer on signals, 
> but the bus goes
>  	 * into arbitration and we're currently unable to 
> recover from it.
>  	 */
> +	if (dev->set_mpu_wkup_lat != NULL)
> +		dev->set_mpu_wkup_lat(dev->dev, dev->latency);
>  	r = wait_for_completion_timeout(&dev->cmd_complete,
>  					OMAP_I2C_TIMEOUT);
> +	if (dev->set_mpu_wkup_lat != NULL)
> +		dev->set_mpu_wkup_lat(dev->dev, -1);
>  	dev->buf_len = 0;
>  	if (r < 0)
>  		return r;
> @@ -826,6 +834,7 @@ omap_i2c_probe(struct platform_device *pdev)
>  	struct omap_i2c_dev	*dev;
>  	struct i2c_adapter	*adap;
>  	struct resource		*mem, *irq, *ioarea;
> +	struct omap_i2c_bus_platform_data *pdata = 
> pdev->dev.platform_data;
>  	irq_handler_t isr;
>  	int r;
>  	u32 speed = 0;
> @@ -855,10 +864,13 @@ omap_i2c_probe(struct platform_device *pdev)
>  		goto err_release_region;
>  	}
>  
> -	if (pdev->dev.platform_data != NULL)
> -		speed = *(u32 *)pdev->dev.platform_data;
> -	else
> -		speed = 100;	/* Defualt speed */
> +	if (pdata != NULL) {
> +		speed = pdata->clkrate;
> +		dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
> +	} else {
> +		speed = 100;	/* Default speed */
> +		dev->set_mpu_wkup_lat = NULL;
> +	}
>  
>  	dev->speed = speed;
>  	dev->idle = 1;
> @@ -893,6 +905,11 @@ omap_i2c_probe(struct platform_device *pdev)
>  		 */
>  		dev->fifo_size = (dev->fifo_size / 2);
>  		dev->b_hw = 1; /* Enable hardware fixes */
> +
> +		/* calculate wakeup latency constraint for MPU */
> +		if (dev->set_mpu_wkup_lat != NULL)
> +			dev->latency = (1000000 * dev->fifo_size) /
> +				       (1000 * speed / 8);
>  	}
>  
>  	/* reset ASAP, clearing any IRQs */
> diff --git a/include/linux/i2c-omap.h 
> b/include/linux/i2c-omap.h new file mode 100644 index 0000000..1362fba
> --- /dev/null
> +++ b/include/linux/i2c-omap.h
> @@ -0,0 +1,9 @@
> +#ifndef __I2C_OMAP_H__
> +#define __I2C_OMAP_H__
> +
> +struct omap_i2c_bus_platform_data {
> +	u32		clkrate;
> +	void		(*set_mpu_wkup_lat)(struct device *dev, 
> int set);
> +};
> +
> +#endif
> --
> 1.6.3.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-omap" in the body of a message to 
> majordomo@xxxxxxxxxxxxxxx More majordomo info at  
> http://vger.kernel.org/majordomo-info.html
> --
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[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