i2c-algo-pcf: Multi-master lost-arbitration improvement
Improve lost-arbitration handling of PCF8584. This is necessary for support of a currently out-of-kernel driver for Sun Microsystems E250 environmental management; perhaps others. Signed-off-by: Eric Brower <ebrower@gmail.com> Acked-by: Dan Smolik <marvin@mydatex.cz> Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
committed by
Jean Delvare
parent
8a56ce1033
commit
0573d11b2b
@@ -78,6 +78,36 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap)
|
|||||||
set_pcf(adap, 1, I2C_PCF_STOP);
|
set_pcf(adap, 1, I2C_PCF_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
|
||||||
|
{
|
||||||
|
DEB2(printk(KERN_INFO
|
||||||
|
"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
|
||||||
|
*status));
|
||||||
|
|
||||||
|
/* Cleanup from LAB -- reset and enable ESO.
|
||||||
|
* This resets the PCF8584; since we've lost the bus, no
|
||||||
|
* further attempts should be made by callers to clean up
|
||||||
|
* (no i2c_stop() etc.)
|
||||||
|
*/
|
||||||
|
set_pcf(adap, 1, I2C_PCF_PIN);
|
||||||
|
set_pcf(adap, 1, I2C_PCF_ESO);
|
||||||
|
|
||||||
|
/* We pause for a time period sufficient for any running
|
||||||
|
* I2C transaction to complete -- the arbitration logic won't
|
||||||
|
* work properly until the next START is seen.
|
||||||
|
* It is assumed the bus driver or client has set a proper value.
|
||||||
|
*
|
||||||
|
* REVISIT: should probably use msleep instead of mdelay if we
|
||||||
|
* know we can sleep.
|
||||||
|
*/
|
||||||
|
if (adap->lab_mdelay)
|
||||||
|
mdelay(adap->lab_mdelay);
|
||||||
|
|
||||||
|
DEB2(printk(KERN_INFO
|
||||||
|
"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
|
||||||
|
get_pcf(adap, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
|
static int wait_for_bb(struct i2c_algo_pcf_data *adap) {
|
||||||
|
|
||||||
int timeout = DEF_TIMEOUT;
|
int timeout = DEF_TIMEOUT;
|
||||||
@@ -109,23 +139,7 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) {
|
|||||||
*status = get_pcf(adap, 1);
|
*status = get_pcf(adap, 1);
|
||||||
}
|
}
|
||||||
if (*status & I2C_PCF_LAB) {
|
if (*status & I2C_PCF_LAB) {
|
||||||
DEB2(printk(KERN_INFO
|
handle_lab(adap, status);
|
||||||
"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
|
|
||||||
*status));
|
|
||||||
/* Cleanup from LAB-- reset and enable ESO.
|
|
||||||
* This resets the PCF8584; since we've lost the bus, no
|
|
||||||
* further attempts should be made by callers to clean up
|
|
||||||
* (no i2c_stop() etc.)
|
|
||||||
*/
|
|
||||||
set_pcf(adap, 1, I2C_PCF_PIN);
|
|
||||||
set_pcf(adap, 1, I2C_PCF_ESO);
|
|
||||||
/* TODO: we should pause for a time period sufficient for any
|
|
||||||
* running I2C transaction to complete-- the arbitration
|
|
||||||
* logic won't work properly until the next START is seen.
|
|
||||||
*/
|
|
||||||
DEB2(printk(KERN_INFO
|
|
||||||
"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
|
|
||||||
get_pcf(adap,1)));
|
|
||||||
return(-EINTR);
|
return(-EINTR);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -36,6 +36,12 @@ struct i2c_algo_pcf_data {
|
|||||||
/* local settings */
|
/* local settings */
|
||||||
int udelay;
|
int udelay;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
|
/* Multi-master lost arbitration back-off delay (msecs)
|
||||||
|
* This should be set by the bus adapter or knowledgable client
|
||||||
|
* if bus is multi-mastered, else zero
|
||||||
|
*/
|
||||||
|
unsigned long lab_mdelay;
|
||||||
};
|
};
|
||||||
|
|
||||||
int i2c_pcf_add_bus(struct i2c_adapter *);
|
int i2c_pcf_add_bus(struct i2c_adapter *);
|
||||||
|
Reference in New Issue
Block a user