diff options
-rw-r--r-- | drivers/i2c/algos/i2c-algo-pcf.c | 48 | ||||
-rw-r--r-- | include/linux/i2c-algo-pcf.h | 6 |
2 files changed, 37 insertions, 17 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 8907b0191677..1e328d19cd6d 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c | |||
@@ -78,6 +78,36 @@ static void i2c_stop(struct i2c_algo_pcf_data *adap) | |||
78 | set_pcf(adap, 1, I2C_PCF_STOP); | 78 | set_pcf(adap, 1, I2C_PCF_STOP); |
79 | } | 79 | } |
80 | 80 | ||
81 | static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) | ||
82 | { | ||
83 | DEB2(printk(KERN_INFO | ||
84 | "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", | ||
85 | *status)); | ||
86 | |||
87 | /* Cleanup from LAB -- reset and enable ESO. | ||
88 | * This resets the PCF8584; since we've lost the bus, no | ||
89 | * further attempts should be made by callers to clean up | ||
90 | * (no i2c_stop() etc.) | ||
91 | */ | ||
92 | set_pcf(adap, 1, I2C_PCF_PIN); | ||
93 | set_pcf(adap, 1, I2C_PCF_ESO); | ||
94 | |||
95 | /* We pause for a time period sufficient for any running | ||
96 | * I2C transaction to complete -- the arbitration logic won't | ||
97 | * work properly until the next START is seen. | ||
98 | * It is assumed the bus driver or client has set a proper value. | ||
99 | * | ||
100 | * REVISIT: should probably use msleep instead of mdelay if we | ||
101 | * know we can sleep. | ||
102 | */ | ||
103 | if (adap->lab_mdelay) | ||
104 | mdelay(adap->lab_mdelay); | ||
105 | |||
106 | DEB2(printk(KERN_INFO | ||
107 | "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", | ||
108 | get_pcf(adap, 1))); | ||
109 | } | ||
110 | |||
81 | static int wait_for_bb(struct i2c_algo_pcf_data *adap) { | 111 | static int wait_for_bb(struct i2c_algo_pcf_data *adap) { |
82 | 112 | ||
83 | int timeout = DEF_TIMEOUT; | 113 | int timeout = DEF_TIMEOUT; |
@@ -109,23 +139,7 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { | |||
109 | *status = get_pcf(adap, 1); | 139 | *status = get_pcf(adap, 1); |
110 | } | 140 | } |
111 | if (*status & I2C_PCF_LAB) { | 141 | if (*status & I2C_PCF_LAB) { |
112 | DEB2(printk(KERN_INFO | 142 | handle_lab(adap, status); |
113 | "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", | ||
114 | *status)); | ||
115 | /* Cleanup from LAB-- reset and enable ESO. | ||
116 | * This resets the PCF8584; since we've lost the bus, no | ||
117 | * further attempts should be made by callers to clean up | ||
118 | * (no i2c_stop() etc.) | ||
119 | */ | ||
120 | set_pcf(adap, 1, I2C_PCF_PIN); | ||
121 | set_pcf(adap, 1, I2C_PCF_ESO); | ||
122 | /* TODO: we should pause for a time period sufficient for any | ||
123 | * running I2C transaction to complete-- the arbitration | ||
124 | * logic won't work properly until the next START is seen. | ||
125 | */ | ||
126 | DEB2(printk(KERN_INFO | ||
127 | "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", | ||
128 | get_pcf(adap,1))); | ||
129 | return(-EINTR); | 143 | return(-EINTR); |
130 | } | 144 | } |
131 | #endif | 145 | #endif |
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h index 77afbb60fd11..74fb6f889a77 100644 --- a/include/linux/i2c-algo-pcf.h +++ b/include/linux/i2c-algo-pcf.h | |||
@@ -36,6 +36,12 @@ struct i2c_algo_pcf_data { | |||
36 | /* local settings */ | 36 | /* local settings */ |
37 | int udelay; | 37 | int udelay; |
38 | int timeout; | 38 | int timeout; |
39 | |||
40 | /* Multi-master lost arbitration back-off delay (msecs) | ||
41 | * This should be set by the bus adapter or knowledgable client | ||
42 | * if bus is multi-mastered, else zero | ||
43 | */ | ||
44 | unsigned long lab_mdelay; | ||
39 | }; | 45 | }; |
40 | 46 | ||
41 | int i2c_pcf_add_bus(struct i2c_adapter *); | 47 | int i2c_pcf_add_bus(struct i2c_adapter *); |