diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-sis630.c')
-rw-r--r-- | drivers/i2c/busses/i2c-sis630.c | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e152d36b94ac..b2fa7415f7e4 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c | |||
@@ -81,6 +81,21 @@ | |||
81 | #define SMB_COUNT 0x07 /* byte count */ | 81 | #define SMB_COUNT 0x07 /* byte count */ |
82 | #define SMB_BYTE 0x08 /* ~0x8F data byte field */ | 82 | #define SMB_BYTE 0x08 /* ~0x8F data byte field */ |
83 | 83 | ||
84 | /* SMB_STS register */ | ||
85 | #define BYTE_DONE_STS 0x10 /* Byte Done Status / Block Array */ | ||
86 | #define SMBCOL_STS 0x04 /* Collision */ | ||
87 | #define SMBERR_STS 0x02 /* Device error */ | ||
88 | |||
89 | /* SMB_CNT register */ | ||
90 | #define MSTO_EN 0x40 /* Host Master Timeout Enable */ | ||
91 | #define SMBCLK_SEL 0x20 /* Host master clock selection */ | ||
92 | #define SMB_PROBE 0x02 /* Bus Probe/Slave busy */ | ||
93 | #define SMB_HOSTBUSY 0x01 /* Host Busy */ | ||
94 | |||
95 | /* SMBHOST_CNT register */ | ||
96 | #define SMB_KILL 0x20 /* Kill */ | ||
97 | #define SMB_START 0x10 /* Start */ | ||
98 | |||
84 | /* register count for request_region | 99 | /* register count for request_region |
85 | * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964 | 100 | * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964 |
86 | */ | 101 | */ |
@@ -140,12 +155,14 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc | |||
140 | int temp; | 155 | int temp; |
141 | 156 | ||
142 | /* Make sure the SMBus host is ready to start transmitting. */ | 157 | /* Make sure the SMBus host is ready to start transmitting. */ |
143 | if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { | 158 | temp = sis630_read(SMB_CNT); |
144 | dev_dbg(&adap->dev, "SMBus busy (%02x).Resetting...\n",temp); | 159 | if ((temp & (SMB_PROBE | SMB_HOSTBUSY)) != 0x00) { |
160 | dev_dbg(&adap->dev, "SMBus busy (%02x). Resetting...\n", temp); | ||
145 | /* kill smbus transaction */ | 161 | /* kill smbus transaction */ |
146 | sis630_write(SMBHOST_CNT, 0x20); | 162 | sis630_write(SMBHOST_CNT, SMB_KILL); |
147 | 163 | ||
148 | if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { | 164 | temp = sis630_read(SMB_CNT); |
165 | if (temp & (SMB_PROBE | SMB_HOSTBUSY)) { | ||
149 | dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); | 166 | dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); |
150 | return -EBUSY; | 167 | return -EBUSY; |
151 | } else { | 168 | } else { |
@@ -160,16 +177,16 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc | |||
160 | 177 | ||
161 | /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ | 178 | /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ |
162 | if (high_clock) | 179 | if (high_clock) |
163 | sis630_write(SMB_CNT, 0x20); | 180 | sis630_write(SMB_CNT, SMBCLK_SEL); |
164 | else | 181 | else |
165 | sis630_write(SMB_CNT, (*oldclock & ~0x40)); | 182 | sis630_write(SMB_CNT, (*oldclock & ~MSTO_EN)); |
166 | 183 | ||
167 | /* clear all sticky bits */ | 184 | /* clear all sticky bits */ |
168 | temp = sis630_read(SMB_STS); | 185 | temp = sis630_read(SMB_STS); |
169 | sis630_write(SMB_STS, temp & 0x1e); | 186 | sis630_write(SMB_STS, temp & 0x1e); |
170 | 187 | ||
171 | /* start the transaction by setting bit 4 and size */ | 188 | /* start the transaction by setting bit 4 and size */ |
172 | sis630_write(SMBHOST_CNT,0x10 | (size & 0x07)); | 189 | sis630_write(SMBHOST_CNT, SMB_START | (size & 0x07)); |
173 | 190 | ||
174 | return 0; | 191 | return 0; |
175 | } | 192 | } |
@@ -183,7 +200,7 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) | |||
183 | msleep(1); | 200 | msleep(1); |
184 | temp = sis630_read(SMB_STS); | 201 | temp = sis630_read(SMB_STS); |
185 | /* check if block transmitted */ | 202 | /* check if block transmitted */ |
186 | if (size == SIS630_BLOCK_DATA && (temp & 0x10)) | 203 | if (size == SIS630_BLOCK_DATA && (temp & BYTE_DONE_STS)) |
187 | break; | 204 | break; |
188 | } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT)); | 205 | } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT)); |
189 | 206 | ||
@@ -193,12 +210,12 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) | |||
193 | result = -ETIMEDOUT; | 210 | result = -ETIMEDOUT; |
194 | } | 211 | } |
195 | 212 | ||
196 | if (temp & 0x02) { | 213 | if (temp & SMBERR_STS) { |
197 | dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); | 214 | dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); |
198 | result = -ENXIO; | 215 | result = -ENXIO; |
199 | } | 216 | } |
200 | 217 | ||
201 | if (temp & 0x04) { | 218 | if (temp & SMBCOL_STS) { |
202 | dev_err(&adap->dev, "Bus collision!\n"); | 219 | dev_err(&adap->dev, "Bus collision!\n"); |
203 | result = -EAGAIN; | 220 | result = -EAGAIN; |
204 | } | 221 | } |
@@ -217,8 +234,8 @@ static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) | |||
217 | * restore old Host Master Clock if high_clock is set | 234 | * restore old Host Master Clock if high_clock is set |
218 | * and oldclock was not 56KHz | 235 | * and oldclock was not 56KHz |
219 | */ | 236 | */ |
220 | if (high_clock && !(oldclock & 0x20)) | 237 | if (high_clock && !(oldclock & SMBCLK_SEL)) |
221 | sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20)); | 238 | sis630_write(SMB_CNT, sis630_read(SMB_CNT) & ~SMBCLK_SEL); |
222 | 239 | ||
223 | dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); | 240 | dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); |
224 | } | 241 | } |
@@ -270,7 +287,7 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat | |||
270 | we must clear sticky bit. | 287 | we must clear sticky bit. |
271 | clear SMBARY_STS | 288 | clear SMBARY_STS |
272 | */ | 289 | */ |
273 | sis630_write(SMB_STS,0x10); | 290 | sis630_write(SMB_STS, BYTE_DONE_STS); |
274 | } | 291 | } |
275 | rc = sis630_transaction_wait(adap, | 292 | rc = sis630_transaction_wait(adap, |
276 | SIS630_BLOCK_DATA); | 293 | SIS630_BLOCK_DATA); |
@@ -312,7 +329,7 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat | |||
312 | dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i); | 329 | dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i); |
313 | 330 | ||
314 | /* clear SMBARY_STS */ | 331 | /* clear SMBARY_STS */ |
315 | sis630_write(SMB_STS,0x10); | 332 | sis630_write(SMB_STS, BYTE_DONE_STS); |
316 | } while(len < data->block[0]); | 333 | } while(len < data->block[0]); |
317 | } | 334 | } |
318 | 335 | ||