i2c-powermac: Refactor i2c_powermac_smbus_xfer

I wanted to add some error logging to the i2c-powermac driver, but
found that it was very difficult due to the way the
i2c_powermac_smbus_xfer function is organized. Refactor the code in
this function so that each low-level function is only called once.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Tested-by: Michel Daenzer <michel@daenzer.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Jean Delvare 2009-12-06 17:06:17 +01:00
parent 6f7e549f87
commit 02864d58ce

View file

@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
int rc = 0; int rc = 0;
int read = (read_write == I2C_SMBUS_READ); int read = (read_write == I2C_SMBUS_READ);
int addrdir = (addr << 1) | read; int addrdir = (addr << 1) | read;
int mode, subsize, len;
u32 subaddr;
u8 *buf;
u8 local[2]; u8 local[2];
rc = pmac_i2c_open(bus, 0); if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
if (rc) mode = pmac_i2c_mode_std;
return rc; subsize = 0;
subaddr = 0;
} else {
mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
subsize = 1;
subaddr = command;
}
switch (size) { switch (size) {
case I2C_SMBUS_QUICK: case I2C_SMBUS_QUICK:
rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); buf = NULL;
if (rc) len = 0;
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0);
break; break;
case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE:
rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1);
break;
case I2C_SMBUS_BYTE_DATA: case I2C_SMBUS_BYTE_DATA:
rc = pmac_i2c_setmode(bus, read ? buf = &data->byte;
pmac_i2c_mode_combined : len = 1;
pmac_i2c_mode_stdsub);
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1);
break; break;
case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_WORD_DATA:
rc = pmac_i2c_setmode(bus, read ?
pmac_i2c_mode_combined :
pmac_i2c_mode_stdsub);
if (rc)
goto bail;
if (!read) { if (!read) {
local[0] = data->word & 0xff; local[0] = data->word & 0xff;
local[1] = (data->word >> 8) & 0xff; local[1] = (data->word >> 8) & 0xff;
} }
rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2); buf = local;
if (rc == 0 && read) { len = 2;
data->word = ((u16)local[1]) << 8;
data->word |= local[0];
}
break; break;
/* Note that these are broken vs. the expected smbus API where /* Note that these are broken vs. the expected smbus API where
@ -105,28 +95,35 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
* a repeat start/addr phase (but not stop in between) * a repeat start/addr phase (but not stop in between)
*/ */
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:
rc = pmac_i2c_setmode(bus, read ? buf = data->block;
pmac_i2c_mode_combined : len = data->block[0] + 1;
pmac_i2c_mode_stdsub);
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block,
data->block[0] + 1);
break; break;
case I2C_SMBUS_I2C_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:
rc = pmac_i2c_setmode(bus, read ? buf = &data->block[1];
pmac_i2c_mode_combined : len = data->block[0];
pmac_i2c_mode_stdsub);
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 1, command,
&data->block[1], data->block[0]);
break; break;
default: default:
rc = -EINVAL; return -EINVAL;
} }
rc = pmac_i2c_open(bus, 0);
if (rc)
return rc;
rc = pmac_i2c_setmode(bus, mode);
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
if (rc)
goto bail;
if (size == I2C_SMBUS_WORD_DATA && read) {
data->word = ((u16)local[1]) << 8;
data->word |= local[0];
}
bail: bail:
pmac_i2c_close(bus); pmac_i2c_close(bus);
return rc; return rc;