diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 59 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 5 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 39 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 48 | 
5 files changed, 99 insertions, 54 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f1c6ca7e285..c8460fa9cfa 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI  config I2C_BLACKFIN_TWI_CLK_KHZ  	int "Blackfin TWI I2C clock (kHz)"  	depends on I2C_BLACKFIN_TWI -	range 10 400 +	range 21 400  	default 50  	help  	  The unit of the TWI clock is kHz. diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fc548b3d002..26d8987e69b 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)  			write_MASTER_CTL(iface,  				read_MASTER_CTL(iface) | STOP);  		else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && -				iface->cur_msg+1 < iface->msg_num) -			write_MASTER_CTL(iface, -				read_MASTER_CTL(iface) | RSTART); +		         iface->cur_msg + 1 < iface->msg_num) { +			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) +				write_MASTER_CTL(iface, +					read_MASTER_CTL(iface) | RSTART | MDIR); +			else +				write_MASTER_CTL(iface, +					(read_MASTER_CTL(iface) | RSTART) & ~MDIR); +		}  		SSYNC();  		/* Clear status */  		write_INT_STAT(iface, XMTSERV); @@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)  				read_MASTER_CTL(iface) | STOP);  			SSYNC();  		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && -				iface->cur_msg+1 < iface->msg_num) { -			write_MASTER_CTL(iface, -				read_MASTER_CTL(iface) | RSTART); +		           iface->cur_msg + 1 < iface->msg_num) { +			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) +				write_MASTER_CTL(iface, +					read_MASTER_CTL(iface) | RSTART | MDIR); +			else +				write_MASTER_CTL(iface, +					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);  			SSYNC();  		}  		/* Clear interrupt source */ @@ -196,8 +205,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)  			/* remove restart bit and enable master receive */  			write_MASTER_CTL(iface,  				read_MASTER_CTL(iface) & ~RSTART); -			write_MASTER_CTL(iface, -				read_MASTER_CTL(iface) | MEN | MDIR);  			SSYNC();  		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&  				iface->cur_msg+1 < iface->msg_num) { @@ -222,18 +229,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)  			}  			if (iface->pmsg[iface->cur_msg].len <= 255) -				write_MASTER_CTL(iface, -				iface->pmsg[iface->cur_msg].len << 6); +					write_MASTER_CTL(iface, +					(read_MASTER_CTL(iface) & +					(~(0xff << 6))) | +				(iface->pmsg[iface->cur_msg].len << 6));  			else { -				write_MASTER_CTL(iface, 0xff << 6); +				write_MASTER_CTL(iface, +					(read_MASTER_CTL(iface) | +					(0xff << 6)));  				iface->manual_stop = 1;  			}  			/* remove restart bit and enable master receive */  			write_MASTER_CTL(iface,  				read_MASTER_CTL(iface) & ~RSTART); -			write_MASTER_CTL(iface, read_MASTER_CTL(iface) | -				MEN | ((iface->read_write == I2C_SMBUS_READ) ? -				MDIR : 0));  			SSYNC();  		} else {  			iface->result = 1; @@ -441,6 +449,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,  		}  		iface->transPtr = data->block;  		break; +	case I2C_SMBUS_I2C_BLOCK_DATA: +		if (read_write == I2C_SMBUS_READ) { +			iface->readNum = data->block[0]; +			iface->cur_mode = TWI_I2C_MODE_COMBINED; +		} else { +			iface->writeNum = data->block[0]; +			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; +		} +		iface->transPtr = (u8 *)&data->block[1]; +		break;  	default:  		return -1;  	} @@ -564,7 +582,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap)  	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |  	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |  	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | -	       I2C_FUNC_I2C; +	       I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;  }  static struct i2c_algorithm bfin_twi_algorithm = { @@ -614,6 +632,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)  	struct i2c_adapter *p_adap;  	struct resource *res;  	int rc; +	unsigned int clkhilow;  	iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);  	if (!iface) { @@ -675,10 +694,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)  	/* Set TWI internal clock as 10MHz */  	write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); +	/* +	 * We will not end up with a CLKDIV=0 because no one will specify +	 * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100) +	 */ +	clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ; +  	/* Set Twi interface clock as specified */ -	write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) -			<< 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) -			& 0xFF)); +	write_CLKDIV(iface, (clkhilow << 8) | clkhilow);  	/* Enable TWI */  	write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index e5193bf7548..3542c6ba98f 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)  	struct ocores_i2c_platform_data *pdata;  	struct resource *res, *res2;  	int ret; +	int i;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) @@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)  		goto add_adapter_failed;  	} +	/* add in known devices to the bus */ +	for (i = 0; i < pdata->num_devices; i++) +		i2c_new_device(&i2c->adap, pdata->devices + i); +  	return 0;  add_adapter_failed: diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ece0125a1ee..c73475dd0fb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)  	if (cpu_is_omap2430() || cpu_is_omap34xx()) { -		/* HSI2C controller internal clk rate should be 19.2 Mhz */ -		internal_clk = 19200; +		/* +		 * HSI2C controller internal clk rate should be 19.2 Mhz for +		 * HS and for all modes on 2430. On 34xx we can use lower rate +		 * to get longer filter period for better noise suppression. +		 * The filter is iclk (fclk for HS) period. +		 */ +		if (dev->speed > 400 || cpu_is_omap_2430()) +			internal_clk = 19200; +		else if (dev->speed > 100) +			internal_clk = 9600; +		else +			internal_clk = 4000;  		fclk_rate = clk_get_rate(dev->fclk) / 1000;  		/* Compute prescaler divisor */ @@ -343,17 +353,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)  		/* If configured for High Speed */  		if (dev->speed > 400) { +			unsigned long scl; +  			/* For first phase of HS mode */ -			fsscll = internal_clk / (400 * 2) - 6; -			fssclh = internal_clk / (400 * 2) - 6; +			scl = internal_clk / 400; +			fsscll = scl - (scl / 3) - 7; +			fssclh = (scl / 3) - 5;  			/* For second phase of HS mode */ -			hsscll = fclk_rate / (dev->speed * 2) - 6; -			hssclh = fclk_rate / (dev->speed * 2) - 6; +			scl = fclk_rate / dev->speed; +			hsscll = scl - (scl / 3) - 7; +			hssclh = (scl / 3) - 5; +		} else if (dev->speed > 100) { +			unsigned long scl; + +			/* Fast mode */ +			scl = internal_clk / dev->speed; +			fsscll = scl - (scl / 3) - 7; +			fssclh = (scl / 3) - 5;  		} else { -			/* To handle F/S modes */ -			fsscll = internal_clk / (dev->speed * 2) - 6; -			fssclh = internal_clk / (dev->speed * 2) - 6; +			/* Standard mode */ +			fsscll = internal_clk / (dev->speed * 2) - 7; +			fssclh = internal_clk / (dev->speed * 2) - 5;  		}  		scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;  		sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1691ef0f1ee..079a312d36f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -51,6 +51,11 @@ enum s3c24xx_i2c_state {  	STATE_STOP  }; +enum s3c24xx_i2c_type { +	TYPE_S3C2410, +	TYPE_S3C2440, +}; +  struct s3c24xx_i2c {  	spinlock_t		lock;  	wait_queue_head_t	wait; @@ -88,8 +93,10 @@ struct s3c24xx_i2c {  static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)  {  	struct platform_device *pdev = to_platform_device(i2c->dev); +	enum s3c24xx_i2c_type type; -	return !strcmp(pdev->name, "s3c2440-i2c"); +	type = platform_get_device_id(pdev)->driver_data; +	return type == TYPE_S3C2440;  }  /* s3c24xx_i2c_master_complete @@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev)  /* device driver for platform bus bits */ -static struct platform_driver s3c2410_i2c_driver = { -	.probe		= s3c24xx_i2c_probe, -	.remove		= s3c24xx_i2c_remove, -	.suspend_late	= s3c24xx_i2c_suspend_late, -	.resume		= s3c24xx_i2c_resume, -	.driver		= { -		.owner	= THIS_MODULE, -		.name	= "s3c2410-i2c", -	}, +static struct platform_device_id s3c24xx_driver_ids[] = { +	{ +		.name		= "s3c2410-i2c", +		.driver_data	= TYPE_S3C2410, +	}, { +		.name		= "s3c2440-i2c", +		.driver_data	= TYPE_S3C2440, +	}, { },  }; +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static struct platform_driver s3c2440_i2c_driver = { +static struct platform_driver s3c24xx_i2c_driver = {  	.probe		= s3c24xx_i2c_probe,  	.remove		= s3c24xx_i2c_remove,  	.suspend_late	= s3c24xx_i2c_suspend_late,  	.resume		= s3c24xx_i2c_resume, +	.id_table	= s3c24xx_driver_ids,  	.driver		= {  		.owner	= THIS_MODULE, -		.name	= "s3c2440-i2c", +		.name	= "s3c-i2c",  	},  };  static int __init i2c_adap_s3c_init(void)  { -	int ret; - -	ret = platform_driver_register(&s3c2410_i2c_driver); -	if (ret == 0) { -		ret = platform_driver_register(&s3c2440_i2c_driver); -		if (ret) -			platform_driver_unregister(&s3c2410_i2c_driver); -	} - -	return ret; +	return platform_driver_register(&s3c24xx_i2c_driver);  }  subsys_initcall(i2c_adap_s3c_init);  static void __exit i2c_adap_s3c_exit(void)  { -	platform_driver_unregister(&s3c2410_i2c_driver); -	platform_driver_unregister(&s3c2440_i2c_driver); +	platform_driver_unregister(&s3c24xx_i2c_driver);  }  module_exit(i2c_adap_s3c_exit);  MODULE_DESCRIPTION("S3C24XX I2C Bus driver");  MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");  MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-i2c"); -MODULE_ALIAS("platform:s3c2440-i2c");  | 
