diff options
Diffstat (limited to 'drivers/i2c/i2c-core.c')
| -rw-r--r-- | drivers/i2c/i2c-core.c | 199 | 
1 files changed, 72 insertions, 127 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dda472e5e8b..82ea1b7ec91 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -19,7 +19,8 @@  /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.     All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> -   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com>                */ +   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and +   Jean Delvare <khali@linux-fr.org> */  #include <linux/module.h>  #include <linux/kernel.h> @@ -29,6 +30,7 @@  #include <linux/init.h>  #include <linux/idr.h>  #include <linux/seq_file.h> +#include <linux/platform_device.h>  #include <asm/uaccess.h> @@ -48,7 +50,7 @@ static int i2c_bus_suspend(struct device * dev, pm_message_t state)  	int rc = 0;  	if (dev->driver && dev->driver->suspend) -		rc = dev->driver->suspend(dev,state,0); +		rc = dev->driver->suspend(dev, state);  	return rc;  } @@ -57,7 +59,7 @@ static int i2c_bus_resume(struct device * dev)  	int rc = 0;  	if (dev->driver && dev->driver->resume) -		rc = dev->driver->resume(dev,0); +		rc = dev->driver->resume(dev);  	return rc;  } @@ -85,6 +87,7 @@ void i2c_adapter_dev_release(struct device *dev)  }  struct device_driver i2c_adapter_driver = { +	.owner = THIS_MODULE,  	.name =	"i2c_adapter",  	.bus = &i2c_bus_type,  	.probe = i2c_device_probe, @@ -98,6 +101,7 @@ static void i2c_adapter_class_dev_release(struct class_device *dev)  }  struct class i2c_adapter_class = { +	.owner =	THIS_MODULE,  	.name =		"i2c-adapter",  	.release =	&i2c_adapter_class_dev_release,  }; @@ -291,6 +295,7 @@ int i2c_add_driver(struct i2c_driver *driver)  	down(&core_lists);  	/* add the driver to the list of i2c drivers in the driver core */ +	driver->driver.owner = driver->owner;  	driver->driver.name = driver->name;  	driver->driver.bus = &i2c_bus_type;  	driver->driver.probe = i2c_device_probe; @@ -706,10 +711,6 @@ int i2c_probe(struct i2c_adapter *adapter,  	int i, err;  	int adap_id = i2c_adapter_id(adapter); -	/* Forget it if we can't probe using SMBUS_QUICK */ -	if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) -		return -1; -  	/* Force entries are done first, and are not affected by ignore  	   entries */  	if (address_data->forces) { @@ -736,6 +737,17 @@ int i2c_probe(struct i2c_adapter *adapter,  		}  	} +	/* Stop here if we can't use SMBUS_QUICK */ +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { +		if (address_data->probe[0] == I2C_CLIENT_END +		 && address_data->normal_i2c[0] == I2C_CLIENT_END) +		 	return 0; + +		dev_warn(&adapter->dev, "SMBus Quick command not supported, " +			 "can't probe for chips\n"); +		return -1; +	} +  	/* Probe entries are done second, and are not affected by ignore  	   entries either */  	for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { @@ -820,101 +832,44 @@ crc8(u16 data)  	return (u8)(data >> 8);  } -/* CRC over count bytes in the first array plus the bytes in the rest -   array if it is non-null. rest[0] is the (length of rest) - 1 -   and is included. */ -static u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +/* Incremental CRC8 over count bytes in the array pointed to by p */ +static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)  {  	int i;  	for(i = 0; i < count; i++) -		crc = crc8((crc ^ first[i]) << 8); -	if(rest != NULL) -		for(i = 0; i <= rest[0]; i++) -			crc = crc8((crc ^ rest[i]) << 8); +		crc = crc8((crc ^ p[i]) << 8);  	return crc;  } -static u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +/* Assume a 7-bit address, which is reasonable for SMBus */ +static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)  { -	return i2c_smbus_partial_pec(0, count, first, rest); +	/* The address will be sent first */ +	u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); +	pec = i2c_smbus_pec(pec, &addr, 1); + +	/* The data buffer follows */ +	return i2c_smbus_pec(pec, msg->buf, msg->len);  } -/* Returns new "size" (transaction type) -   Note that we convert byte to byte_data and byte_data to word_data -   rather than invent new xxx_PEC transactions. */ -static int i2c_smbus_add_pec(u16 addr, u8 command, int size, -			     union i2c_smbus_data *data) +/* Used for write only transactions */ +static inline void i2c_smbus_add_pec(struct i2c_msg *msg)  { -	u8 buf[3]; - -	buf[0] = addr << 1; -	buf[1] = command; -	switch(size) { -		case I2C_SMBUS_BYTE: -			data->byte = i2c_smbus_pec(2, buf, NULL); -			size = I2C_SMBUS_BYTE_DATA; -			break; -		case I2C_SMBUS_BYTE_DATA: -			buf[2] = data->byte; -			data->word = buf[2] || -			            (i2c_smbus_pec(3, buf, NULL) << 8); -			size = I2C_SMBUS_WORD_DATA; -			break; -		case I2C_SMBUS_WORD_DATA: -			/* unsupported */ -			break; -		case I2C_SMBUS_BLOCK_DATA: -			data->block[data->block[0] + 1] = -			             i2c_smbus_pec(2, buf, data->block); -			size = I2C_SMBUS_BLOCK_DATA_PEC; -			break; -	} -	return size;	 +	msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); +	msg->len++;  } -static int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, -			       union i2c_smbus_data *data) +/* Return <0 on CRC error +   If there was a write before this read (most cases) we need to take the +   partial CRC from the write part into account. +   Note that this function does modify the message (we need to decrease the +   message length to hide the CRC byte from the caller). */ +static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)  { -	u8 buf[3], rpec, cpec; +	u8 rpec = msg->buf[--msg->len]; +	cpec = i2c_smbus_msg_pec(cpec, msg); -	buf[1] = command; -	switch(size) { -		case I2C_SMBUS_BYTE_DATA: -			buf[0] = (addr << 1) | 1; -			cpec = i2c_smbus_pec(2, buf, NULL); -			rpec = data->byte; -			break; -		case I2C_SMBUS_WORD_DATA: -			buf[0] = (addr << 1) | 1; -			buf[2] = data->word & 0xff; -			cpec = i2c_smbus_pec(3, buf, NULL); -			rpec = data->word >> 8; -			break; -		case I2C_SMBUS_WORD_DATA_PEC: -			/* unsupported */ -			cpec = rpec = 0; -			break; -		case I2C_SMBUS_PROC_CALL_PEC: -			/* unsupported */ -			cpec = rpec = 0; -			break; -		case I2C_SMBUS_BLOCK_DATA_PEC: -			buf[0] = (addr << 1); -			buf[2] = (addr << 1) | 1; -			cpec = i2c_smbus_pec(3, buf, data->block); -			rpec = data->block[data->block[0] + 1]; -			break; -		case I2C_SMBUS_BLOCK_PROC_CALL_PEC: -			buf[0] = (addr << 1) | 1; -			rpec = i2c_smbus_partial_pec(partial, 1, -			                             buf, data->block); -			cpec = data->block[data->block[0] + 1]; -			break; -		default: -			cpec = rpec = 0; -			break; -	}  	if (rpec != cpec) {  		pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",  			rpec, cpec); @@ -941,9 +896,8 @@ s32 i2c_smbus_read_byte(struct i2c_client *client)  s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)  { -	union i2c_smbus_data data;	/* only for PEC */  	return i2c_smbus_xfer(client->adapter,client->addr,client->flags, -	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); +	                      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);  }  s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) @@ -1026,13 +980,14 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,  	  need to use only one message; when reading, we need two. We initialize  	  most things with sane defaults, to keep the code below somewhat  	  simpler. */ -	unsigned char msgbuf0[34]; -	unsigned char msgbuf1[34]; +	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; +	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];  	int num = read_write == I2C_SMBUS_READ?2:1;  	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },   	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }  	                        };  	int i; +	u8 partial_pec = 0;  	msgbuf0[0] = command;  	switch(size) { @@ -1075,7 +1030,6 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,  		msgbuf0[2] = (data->word >> 8) & 0xff;  		break;  	case I2C_SMBUS_BLOCK_DATA: -	case I2C_SMBUS_BLOCK_DATA_PEC:  		if (read_write == I2C_SMBUS_READ) {  			dev_err(&adapter->dev, "Block read not supported "  			       "under I2C emulation!\n"); @@ -1088,23 +1042,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,  				       data->block[0]);  				return -1;  			} -			if(size == I2C_SMBUS_BLOCK_DATA_PEC) -				(msg[0].len)++; -			for (i = 1; i <= msg[0].len; i++) +			for (i = 1; i < msg[0].len; i++)  				msgbuf0[i] = data->block[i-1];  		}  		break;  	case I2C_SMBUS_BLOCK_PROC_CALL: -	case I2C_SMBUS_BLOCK_PROC_CALL_PEC:  		dev_dbg(&adapter->dev, "Block process call not supported "  		       "under I2C emulation!\n");  		return -1;  	case I2C_SMBUS_I2C_BLOCK_DATA:  		if (read_write == I2C_SMBUS_READ) { -			msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; +			msg[1].len = I2C_SMBUS_BLOCK_MAX;  		} else {  			msg[0].len = data->block[0] + 1; -			if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) { +			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {  				dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "  				       "invalid block write size (%d)\n",  				       data->block[0]); @@ -1120,9 +1071,30 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,  		return -1;  	} +	i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK +				      && size != I2C_SMBUS_I2C_BLOCK_DATA); +	if (i) { +		/* Compute PEC if first message is a write */ +		if (!(msg[0].flags & I2C_M_RD)) { +		 	if (num == 1) /* Write only */ +				i2c_smbus_add_pec(&msg[0]); +			else /* Write followed by read */ +				partial_pec = i2c_smbus_msg_pec(0, &msg[0]); +		} +		/* Ask for PEC if last message is a read */ +		if (msg[num-1].flags & I2C_M_RD) +		 	msg[num-1].len++; +	} +  	if (i2c_transfer(adapter, msg, num) < 0)  		return -1; +	/* Check PEC if last message is a read */ +	if (i && (msg[num-1].flags & I2C_M_RD)) { +		if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0) +			return -1; +	} +  	if (read_write == I2C_SMBUS_READ)  		switch(size) {  			case I2C_SMBUS_BYTE: @@ -1137,8 +1109,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,  				break;  			case I2C_SMBUS_I2C_BLOCK_DATA:  				/* fixed at 32 for now */ -				data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; -				for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) +				data->block[0] = I2C_SMBUS_BLOCK_MAX; +				for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)  					data->block[i+1] = msgbuf1[i];  				break;  		} @@ -1151,28 +1123,8 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,                     union i2c_smbus_data * data)  {  	s32 res; -	int swpec = 0; -	u8 partial = 0;  	flags &= I2C_M_TEN | I2C_CLIENT_PEC; -	if((flags & I2C_CLIENT_PEC) && -	   !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { -		swpec = 1; -		if(read_write == I2C_SMBUS_READ && -		   size == I2C_SMBUS_BLOCK_DATA) -			size = I2C_SMBUS_BLOCK_DATA_PEC; -		else if(size == I2C_SMBUS_PROC_CALL) -			size = I2C_SMBUS_PROC_CALL_PEC; -		else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { -			i2c_smbus_add_pec(addr, command, -		                          I2C_SMBUS_BLOCK_DATA, data); -			partial = data->block[data->block[0] + 1]; -			size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; -		} else if(read_write == I2C_SMBUS_WRITE && -		          size != I2C_SMBUS_QUICK && -		          size != I2C_SMBUS_I2C_BLOCK_DATA) -			size = i2c_smbus_add_pec(addr, command, size, data); -	}  	if (adapter->algo->smbus_xfer) {  		down(&adapter->bus_lock); @@ -1183,13 +1135,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,  		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,  	                                      command,size,data); -	if(res >= 0 && swpec && -	   size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && -	   (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || -	    size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { -		if(i2c_smbus_check_pec(addr, command, size, partial, data)) -			return -1; -	}  	return res;  }  | 
